Merge "Replace API level codename with number"
diff --git a/android/allowlists/allowlists.go b/android/allowlists/allowlists.go
index 5c120e2..ccfad00 100644
--- a/android/allowlists/allowlists.go
+++ b/android/allowlists/allowlists.go
@@ -226,12 +226,14 @@
"build/bazel/ci/dist":/* recursive = */ false,
"build/bazel/examples/android_app":/* recursive = */ true,
"build/bazel/examples/java":/* recursive = */ true,
+ "build/bazel/examples/partitions":/* recursive = */ true,
"build/bazel/bazel_skylib":/* recursive = */ true,
"build/bazel/rules":/* recursive = */ true,
"build/bazel/rules_cc":/* recursive = */ true,
"build/bazel/scripts":/* recursive = */ true,
"build/bazel/tests":/* recursive = */ true,
"build/bazel/platforms":/* recursive = */ true,
+ "build/bazel/product_config":/* recursive = */ true,
"build/bazel/product_variables":/* recursive = */ true,
"build/bazel/vendor/google":/* recursive = */ true,
"build/bazel_common_rules":/* recursive = */ true,
diff --git a/android/arch.go b/android/arch.go
index cbf77c7..382a7df 100644
--- a/android/arch.go
+++ b/android/arch.go
@@ -307,7 +307,7 @@
// Linux is the OS for the Linux kernel plus the glibc runtime.
Linux = newOsType("linux_glibc", Host, false, X86, X86_64)
// LinuxMusl is the OS for the Linux kernel plus the musl runtime.
- LinuxMusl = newOsType("linux_musl", Host, false, X86, X86_64)
+ LinuxMusl = newOsType("linux_musl", Host, false, X86, X86_64, Arm64, Arm)
// Darwin is the OS for MacOS/Darwin host machines.
Darwin = newOsType("darwin", Host, false, Arm64, X86_64)
// LinuxBionic is the OS for the Linux kernel plus the Bionic libc runtime, but without the
diff --git a/android/bazel_handler.go b/android/bazel_handler.go
index 33b67ab..27255d1 100644
--- a/android/bazel_handler.go
+++ b/android/bazel_handler.go
@@ -21,6 +21,7 @@
"io/ioutil"
"os"
"os/exec"
+ "path"
"path/filepath"
"runtime"
"strings"
@@ -528,7 +529,7 @@
configNodesSection := ""
labelsByConfig := map[string][]string{}
- for val, _ := range context.requests {
+ for val := range context.requests {
labelString := fmt.Sprintf("\"@%s\"", val.label)
configString := getConfigString(val)
labelsByConfig[configString] = append(labelsByConfig[configString], labelString)
@@ -566,7 +567,7 @@
// request type.
func (context *bazelContext) cqueryStarlarkFileContents() []byte {
requestTypeToCqueryIdEntries := map[cqueryRequest][]string{}
- for val, _ := range context.requests {
+ for val := range context.requests {
cqueryId := getCqueryId(val)
mapEntryString := fmt.Sprintf("%q : True", cqueryId)
requestTypeToCqueryIdEntries[val.requestType] =
@@ -870,53 +871,14 @@
})
}
- // Register bazel-owned build statements (obtained from the aquery invocation).
+ executionRoot := path.Join(ctx.Config().BazelContext.OutputBase(), "execroot", "__main__")
+ bazelOutDir := path.Join(executionRoot, "bazel-out")
for index, buildStatement := range ctx.Config().BazelContext.BuildStatementsToRegister() {
if len(buildStatement.Command) < 1 {
panic(fmt.Sprintf("unhandled build statement: %v", buildStatement))
}
rule := NewRuleBuilder(pctx, ctx)
- cmd := rule.Command()
-
- // cd into Bazel's execution root, which is the action cwd.
- cmd.Text(fmt.Sprintf("cd %s/execroot/__main__ &&", ctx.Config().BazelContext.OutputBase()))
-
- // Remove old outputs, as some actions might not rerun if the outputs are detected.
- if len(buildStatement.OutputPaths) > 0 {
- cmd.Text("rm -f")
- for _, outputPath := range buildStatement.OutputPaths {
- cmd.Text(outputPath)
- }
- cmd.Text("&&")
- }
-
- for _, pair := range buildStatement.Env {
- // Set per-action env variables, if any.
- cmd.Flag(pair.Key + "=" + pair.Value)
- }
-
- // The actual Bazel action.
- cmd.Text(buildStatement.Command)
-
- for _, outputPath := range buildStatement.OutputPaths {
- cmd.ImplicitOutput(PathForBazelOut(ctx, outputPath))
- }
- for _, inputPath := range buildStatement.InputPaths {
- cmd.Implicit(PathForBazelOut(ctx, inputPath))
- }
- for _, inputDepsetHash := range buildStatement.InputDepsetHashes {
- otherDepsetName := bazelDepsetName(inputDepsetHash)
- cmd.Implicit(PathForPhony(ctx, otherDepsetName))
- }
-
- if depfile := buildStatement.Depfile; depfile != nil {
- cmd.ImplicitDepFile(PathForBazelOut(ctx, *depfile))
- }
-
- for _, symlinkPath := range buildStatement.SymlinkPaths {
- cmd.ImplicitSymlinkOutput(PathForBazelOut(ctx, symlinkPath))
- }
-
+ createCommand(rule.Command(), buildStatement, executionRoot, bazelOutDir, ctx)
// This is required to silence warnings pertaining to unexpected timestamps. Particularly,
// some Bazel builtins (such as files in the bazel_tools directory) have far-future
// timestamps. Without restat, Ninja would emit warnings that the input files of a
@@ -928,6 +890,58 @@
}
}
+// Register bazel-owned build statements (obtained from the aquery invocation).
+func createCommand(cmd *RuleBuilderCommand, buildStatement bazel.BuildStatement, executionRoot string, bazelOutDir string, ctx PathContext) {
+ // executionRoot is the action cwd.
+ cmd.Text(fmt.Sprintf("cd '%s' &&", executionRoot))
+
+ // Remove old outputs, as some actions might not rerun if the outputs are detected.
+ if len(buildStatement.OutputPaths) > 0 {
+ cmd.Text("rm -f")
+ for _, outputPath := range buildStatement.OutputPaths {
+ cmd.Text(outputPath)
+ }
+ cmd.Text("&&")
+ }
+
+ for _, pair := range buildStatement.Env {
+ // Set per-action env variables, if any.
+ cmd.Flag(pair.Key + "=" + pair.Value)
+ }
+
+ // The actual Bazel action.
+ cmd.Text(buildStatement.Command)
+
+ for _, outputPath := range buildStatement.OutputPaths {
+ cmd.ImplicitOutput(PathForBazelOut(ctx, outputPath))
+ }
+ for _, inputPath := range buildStatement.InputPaths {
+ cmd.Implicit(PathForBazelOut(ctx, inputPath))
+ }
+ for _, inputDepsetHash := range buildStatement.InputDepsetHashes {
+ otherDepsetName := bazelDepsetName(inputDepsetHash)
+ cmd.Implicit(PathForPhony(ctx, otherDepsetName))
+ }
+
+ if depfile := buildStatement.Depfile; depfile != nil {
+ // The paths in depfile are relative to `executionRoot`.
+ // Hence, they need to be corrected by replacing "bazel-out"
+ // with the full `bazelOutDir`.
+ // Otherwise, implicit outputs and implicit inputs under "bazel-out/"
+ // would be deemed missing.
+ // (Note: The regexp uses a capture group because the version of sed
+ // does not support a look-behind pattern.)
+ replacement := fmt.Sprintf(`&& sed -i'' -E 's@(^|\s|")bazel-out/@\1%s/@g' '%s'`,
+ bazelOutDir, *depfile)
+ cmd.Text(replacement)
+ cmd.ImplicitDepFile(PathForBazelOut(ctx, *depfile))
+ }
+
+ for _, symlinkPath := range buildStatement.SymlinkPaths {
+ cmd.ImplicitSymlinkOutput(PathForBazelOut(ctx, symlinkPath))
+ }
+}
+
func getCqueryId(key cqueryKey) string {
return key.label + "|" + getConfigString(key)
}
diff --git a/android/bazel_handler_test.go b/android/bazel_handler_test.go
index dd9a7ed..935ce4e 100644
--- a/android/bazel_handler_test.go
+++ b/android/bazel_handler_test.go
@@ -57,8 +57,13 @@
}
func TestInvokeBazelPopulatesBuildStatements(t *testing.T) {
- bazelContext, _ := testBazelContext(t, map[bazelCommand]string{
- bazelCommand{command: "aquery", expression: "deps(@soong_injection//mixed_builds:buildroot)"}: `
+ type testCase struct {
+ input string
+ command string
+ }
+
+ var testCases = []testCase{
+ {`
{
"artifacts": [{
"id": 1,
@@ -88,15 +93,60 @@
"label": "two"
}]
}`,
- })
- err := bazelContext.InvokeBazel(testConfig)
- if err != nil {
- t.Fatalf("Did not expect error invoking Bazel, but got %s", err)
+ "cd 'er' && rm -f one && touch foo",
+ }, {`
+{
+ "artifacts": [{
+ "id": 1,
+ "pathFragmentId": 10
+ }, {
+ "id": 2,
+ "pathFragmentId": 20
+ }],
+ "actions": [{
+ "targetId": 100,
+ "actionKey": "x",
+ "mnemonic": "x",
+ "arguments": ["bogus", "command"],
+ "outputIds": [1, 2],
+ "primaryOutputId": 1
+ }],
+ "pathFragments": [{
+ "id": 10,
+ "label": "one",
+ "parentId": 30
+ }, {
+ "id": 20,
+ "label": "one.d",
+ "parentId": 30
+ }, {
+ "id": 30,
+ "label": "parent"
+ }]
+}`,
+ `cd 'er' && rm -f parent/one && bogus command && sed -i'' -E 's@(^|\s|")bazel-out/@\1bo/@g' 'parent/one.d'`,
+ },
}
- got := bazelContext.BuildStatementsToRegister()
- if want := 1; len(got) != want {
- t.Errorf("Expected %d registered build statements, got %#v", want, got)
+ for _, testCase := range testCases {
+ bazelContext, _ := testBazelContext(t, map[bazelCommand]string{
+ bazelCommand{command: "aquery", expression: "deps(@soong_injection//mixed_builds:buildroot)"}: testCase.input})
+
+ err := bazelContext.InvokeBazel(testConfig)
+ if err != nil {
+ t.Fatalf("Did not expect error invoking Bazel, but got %s", err)
+ }
+
+ got := bazelContext.BuildStatementsToRegister()
+ if want := 1; len(got) != want {
+ t.Errorf("expected %d registered build statements, but got %#v", want, got)
+ }
+
+ cmd := RuleBuilderCommand{}
+ createCommand(&cmd, got[0], "er", "bo", PathContextForTesting(TestConfig("out", nil, "", nil)))
+ if actual := cmd.buf.String(); testCase.command != actual {
+ t.Errorf("expected: [%s], actual: [%s]", testCase.command, actual)
+ }
}
}
diff --git a/android/config.go b/android/config.go
index cd902cb..47346fc 100644
--- a/android/config.go
+++ b/android/config.go
@@ -1697,6 +1697,10 @@
return InList(name, c.config.productVariables.BuildBrokenInputDirModules)
}
+func (c *deviceConfig) BuildBrokenDepfile() bool {
+ return Bool(c.config.productVariables.BuildBrokenDepfile)
+}
+
func (c *deviceConfig) RequiresInsecureExecmemForSwiftshader() bool {
return c.config.productVariables.RequiresInsecureExecmemForSwiftshader
}
diff --git a/android/defaults.go b/android/defaults.go
index 8b121f6..54f44bc 100644
--- a/android/defaults.go
+++ b/android/defaults.go
@@ -15,6 +15,8 @@
package android
import (
+ "bytes"
+ "fmt"
"reflect"
"github.com/google/blueprint"
@@ -67,9 +69,11 @@
// Set the property structures into which defaults will be added.
setProperties(props []interface{}, variableProperties interface{})
- // Apply defaults from the supplied Defaults to the property structures supplied to
+ // Apply defaults from the supplied DefaultsModule to the property structures supplied to
// setProperties(...).
- applyDefaults(TopDownMutatorContext, []Defaults)
+ applyDefaults(TopDownMutatorContext, []DefaultsModule)
+
+ applySingleDefaultsWithTracker(EarlyModuleContext, DefaultsModule, defaultsTrackerFunc)
// Set the hook to be called after any defaults have been applied.
//
@@ -115,9 +119,23 @@
Defaults_visibility []string
}
+// AdditionalDefaultsProperties contains properties of defaults modules which
+// can have other defaults applied.
+type AdditionalDefaultsProperties struct {
+
+ // The list of properties set by the default whose values must not be changed by any module that
+ // applies these defaults. It is an error if a property is not supported by the defaults module or
+ // has not been set to a non-zero value. If this contains "*" then that must be the only entry in
+ // which case all properties that are set on this defaults will be protected (except the
+ // protected_properties and visibility.
+ Protected_properties []string
+}
+
type DefaultsModuleBase struct {
DefaultableModuleBase
+ defaultsProperties AdditionalDefaultsProperties
+
// Included to support setting bazel_module.label for multiple Soong modules to the same Bazel
// target. This is primarily useful for modules that were architecture specific and instead are
// handled in Bazel as a select().
@@ -151,6 +169,18 @@
// DefaultsModuleBase will type-assert to the Defaults interface.
isDefaults() bool
+ // additionalDefaultableProperties returns additional properties provided by the defaults which
+ // can themselves have defaults applied.
+ additionalDefaultableProperties() []interface{}
+
+ // protectedProperties returns the names of the properties whose values cannot be changed by a
+ // module that applies these defaults.
+ protectedProperties() []string
+
+ // setProtectedProperties sets the names of the properties whose values cannot be changed by a
+ // module that applies these defaults.
+ setProtectedProperties(protectedProperties []string)
+
// Get the structures containing the properties for which defaults can be provided.
properties() []interface{}
@@ -167,6 +197,18 @@
Bazelable
}
+func (d *DefaultsModuleBase) additionalDefaultableProperties() []interface{} {
+ return []interface{}{&d.defaultsProperties}
+}
+
+func (d *DefaultsModuleBase) protectedProperties() []string {
+ return d.defaultsProperties.Protected_properties
+}
+
+func (d *DefaultsModuleBase) setProtectedProperties(protectedProperties []string) {
+ d.defaultsProperties.Protected_properties = protectedProperties
+}
+
func (d *DefaultsModuleBase) properties() []interface{} {
return d.defaultableProperties
}
@@ -190,6 +232,10 @@
&ApexProperties{},
&distProperties{})
+ // Additional properties of defaults modules that can themselves have
+ // defaults applied.
+ module.AddProperties(module.additionalDefaultableProperties()...)
+
// Bazel module must be initialized _before_ Defaults to be included in cc_defaults module.
InitBazelModule(module)
initAndroidModuleBase(module)
@@ -218,6 +264,57 @@
// The applicable licenses property for defaults is 'licenses'.
setPrimaryLicensesProperty(module, "licenses", &commonProperties.Licenses)
+ AddLoadHook(module, func(ctx LoadHookContext) {
+
+ protectedProperties := module.protectedProperties()
+ if len(protectedProperties) == 0 {
+ return
+ }
+
+ propertiesAvailable := map[string]struct{}{}
+ propertiesSet := map[string]struct{}{}
+
+ // A defaults tracker which will keep track of which properties have been set on this module.
+ collector := func(defaults DefaultsModule, property string, dstValue interface{}, srcValue interface{}) bool {
+ value := reflect.ValueOf(dstValue)
+ propertiesAvailable[property] = struct{}{}
+ if !value.IsZero() {
+ propertiesSet[property] = struct{}{}
+ }
+ // Skip all the properties so that there are no changes to the defaults.
+ return false
+ }
+
+ // Try and apply this module's defaults to itself, so that the properties can be collected but
+ // skip all the properties so it doesn't actually do anything.
+ module.applySingleDefaultsWithTracker(ctx, module, collector)
+
+ if InList("*", protectedProperties) {
+ if len(protectedProperties) != 1 {
+ ctx.PropertyErrorf("protected_properties", `if specified then "*" must be the only property listed`)
+ return
+ }
+
+ // Do not automatically protect the protected_properties property.
+ delete(propertiesSet, "protected_properties")
+
+ // Or the visibility property.
+ delete(propertiesSet, "visibility")
+
+ // Replace the "*" with the names of all the properties that have been set.
+ protectedProperties = SortedStringKeys(propertiesSet)
+ module.setProtectedProperties(protectedProperties)
+ } else {
+ for _, property := range protectedProperties {
+ if _, ok := propertiesAvailable[property]; !ok {
+ ctx.PropertyErrorf(property, "property is not supported by this module type %q",
+ ctx.ModuleType())
+ } else if _, ok := propertiesSet[property]; !ok {
+ ctx.PropertyErrorf(property, "is not set; protected properties must be explicitly set")
+ }
+ }
+ }
+ })
}
var _ Defaults = (*DefaultsModuleBase)(nil)
@@ -269,35 +366,204 @@
b.setNamespacedVariableProps(dst)
}
+// defaultValueInfo contains information about each default value that applies to a protected
+// property.
+type defaultValueInfo struct {
+ // The DefaultsModule providing the value, which may be defined on that module or applied as a
+ // default from other modules.
+ module Module
+
+ // The default value, as returned by getComparableValue
+ defaultValue reflect.Value
+}
+
+// protectedPropertyInfo contains information about each property that has to be protected when
+// applying defaults.
+type protectedPropertyInfo struct {
+ // True if the property was set on the module to which defaults are applied, this is an error.
+ propertySet bool
+
+ // The original value of the property on the module, as returned by getComparableValue.
+ originalValue reflect.Value
+
+ // A list of defaults for the property that are being applied.
+ defaultValues []defaultValueInfo
+}
+
+// getComparableValue takes a reflect.Value that may be a pointer to another value and returns a
+// reflect.Value to the underlying data or the original if was not a pointer or was nil. The
+// returned values can then be compared for equality.
+func getComparableValue(value reflect.Value) reflect.Value {
+ if value.IsZero() {
+ return value
+ }
+ for value.Kind() == reflect.Ptr {
+ value = value.Elem()
+ }
+ return value
+}
+
func (defaultable *DefaultableModuleBase) applyDefaults(ctx TopDownMutatorContext,
- defaultsList []Defaults) {
+ defaultsList []DefaultsModule) {
+
+ // Collate information on all the properties protected by each of the default modules applied
+ // to this module.
+ allProtectedProperties := map[string]*protectedPropertyInfo{}
+ for _, defaults := range defaultsList {
+ for _, property := range defaults.protectedProperties() {
+ info := allProtectedProperties[property]
+ if info == nil {
+ info = &protectedPropertyInfo{}
+ allProtectedProperties[property] = info
+ }
+ }
+ }
+
+ // If there are any protected properties then collate information about attempts to change them.
+ var protectedPropertyInfoCollector defaultsTrackerFunc
+ if len(allProtectedProperties) > 0 {
+ protectedPropertyInfoCollector = func(defaults DefaultsModule, property string,
+ dstValue interface{}, srcValue interface{}) bool {
+
+ // If the property is not protected then return immediately.
+ info := allProtectedProperties[property]
+ if info == nil {
+ return true
+ }
+
+ currentValue := reflect.ValueOf(dstValue)
+ if info.defaultValues == nil {
+ info.propertySet = !currentValue.IsZero()
+ info.originalValue = getComparableValue(currentValue)
+ }
+
+ defaultValue := reflect.ValueOf(srcValue)
+ if !defaultValue.IsZero() {
+ info.defaultValues = append(info.defaultValues,
+ defaultValueInfo{defaults, getComparableValue(defaultValue)})
+ }
+
+ return true
+ }
+ }
for _, defaults := range defaultsList {
if ctx.Config().runningAsBp2Build {
applyNamespacedVariableDefaults(defaults, ctx)
}
- for _, prop := range defaultable.defaultableProperties {
- if prop == defaultable.defaultableVariableProperties {
- defaultable.applyDefaultVariableProperties(ctx, defaults, prop)
- } else {
- defaultable.applyDefaultProperties(ctx, defaults, prop)
+
+ defaultable.applySingleDefaultsWithTracker(ctx, defaults, protectedPropertyInfoCollector)
+ }
+
+ // Check the status of any protected properties.
+ for property, info := range allProtectedProperties {
+ if len(info.defaultValues) == 0 {
+ // No defaults were applied to the protected properties. Possibly because this module type
+ // does not support any of them.
+ continue
+ }
+
+ // Check to make sure that there are no conflicts between the defaults.
+ conflictingDefaults := false
+ previousDefaultValue := reflect.ValueOf(false)
+ for _, defaultInfo := range info.defaultValues {
+ defaultValue := defaultInfo.defaultValue
+ if previousDefaultValue.IsZero() {
+ previousDefaultValue = defaultValue
+ } else if !reflect.DeepEqual(previousDefaultValue.Interface(), defaultValue.Interface()) {
+ conflictingDefaults = true
+ break
}
}
+
+ if conflictingDefaults {
+ var buf bytes.Buffer
+ for _, defaultInfo := range info.defaultValues {
+ buf.WriteString(fmt.Sprintf("\n defaults module %q provides value %#v",
+ ctx.OtherModuleName(defaultInfo.module), defaultInfo.defaultValue))
+ }
+ result := buf.String()
+ ctx.ModuleErrorf("has conflicting default values for protected property %q:%s", property, result)
+ continue
+ }
+
+ // Now check to see whether there the current module tried to override/append to the defaults.
+ if info.propertySet {
+ originalValue := info.originalValue
+ // Just compare against the first defaults.
+ defaultValue := info.defaultValues[0].defaultValue
+ defaults := info.defaultValues[0].module
+
+ if originalValue.Kind() == reflect.Slice {
+ ctx.ModuleErrorf("attempts to append %q to protected property %q's value of %q defined in module %q",
+ originalValue,
+ property,
+ defaultValue,
+ ctx.OtherModuleName(defaults))
+ } else {
+ same := reflect.DeepEqual(originalValue.Interface(), defaultValue.Interface())
+ message := ""
+ if same {
+ message = fmt.Sprintf(" with a matching value (%#v) so this property can simply be removed.", originalValue)
+ } else {
+ message = fmt.Sprintf(" with a different value (override %#v with %#v) so removing the property may necessitate other changes.", defaultValue, originalValue)
+ }
+ ctx.ModuleErrorf("attempts to override protected property %q defined in module %q%s",
+ property,
+ ctx.OtherModuleName(defaults), message)
+ }
+ }
+ }
+}
+
+func (defaultable *DefaultableModuleBase) applySingleDefaultsWithTracker(ctx EarlyModuleContext, defaults DefaultsModule, tracker defaultsTrackerFunc) {
+ for _, prop := range defaultable.defaultableProperties {
+ var err error
+ if prop == defaultable.defaultableVariableProperties {
+ err = defaultable.applyDefaultVariableProperties(defaults, prop, tracker)
+ } else {
+ err = defaultable.applyDefaultProperties(defaults, prop, tracker)
+ }
+ if err != nil {
+ if propertyErr, ok := err.(*proptools.ExtendPropertyError); ok {
+ ctx.PropertyErrorf(propertyErr.Property, "%s", propertyErr.Err.Error())
+ } else {
+ panic(err)
+ }
+ }
+ }
+}
+
+// defaultsTrackerFunc is the type of a function that can be used to track how defaults are applied.
+type defaultsTrackerFunc func(defaults DefaultsModule, property string,
+ dstValue interface{}, srcValue interface{}) bool
+
+// filterForTracker wraps a defaultsTrackerFunc in a proptools.ExtendPropertyFilterFunc
+func filterForTracker(defaults DefaultsModule, tracker defaultsTrackerFunc) proptools.ExtendPropertyFilterFunc {
+ if tracker == nil {
+ return nil
+ }
+ return func(property string,
+ dstField, srcField reflect.StructField,
+ dstValue, srcValue interface{}) (bool, error) {
+
+ apply := tracker(defaults, property, dstValue, srcValue)
+ return apply, nil
}
}
// Product variable properties need special handling, the type of the filtered product variable
// property struct may not be identical between the defaults module and the defaultable module.
// Use PrependMatchingProperties to apply whichever properties match.
-func (defaultable *DefaultableModuleBase) applyDefaultVariableProperties(ctx TopDownMutatorContext,
- defaults Defaults, defaultableProp interface{}) {
+func (defaultable *DefaultableModuleBase) applyDefaultVariableProperties(defaults DefaultsModule,
+ defaultableProp interface{}, tracker defaultsTrackerFunc) error {
if defaultableProp == nil {
- return
+ return nil
}
defaultsProp := defaults.productVariableProperties()
if defaultsProp == nil {
- return
+ return nil
}
dst := []interface{}{
@@ -307,31 +573,26 @@
proptools.CloneEmptyProperties(reflect.ValueOf(defaultsProp)).Interface(),
}
- err := proptools.PrependMatchingProperties(dst, defaultsProp, nil)
- if err != nil {
- if propertyErr, ok := err.(*proptools.ExtendPropertyError); ok {
- ctx.PropertyErrorf(propertyErr.Property, "%s", propertyErr.Err.Error())
- } else {
- panic(err)
- }
- }
+ filter := filterForTracker(defaults, tracker)
+
+ return proptools.PrependMatchingProperties(dst, defaultsProp, filter)
}
-func (defaultable *DefaultableModuleBase) applyDefaultProperties(ctx TopDownMutatorContext,
- defaults Defaults, defaultableProp interface{}) {
+func (defaultable *DefaultableModuleBase) applyDefaultProperties(defaults DefaultsModule,
+ defaultableProp interface{}, checker defaultsTrackerFunc) error {
+
+ filter := filterForTracker(defaults, checker)
for _, def := range defaults.properties() {
if proptools.TypeEqual(defaultableProp, def) {
- err := proptools.PrependProperties(defaultableProp, def, nil)
+ err := proptools.PrependProperties(defaultableProp, def, filter)
if err != nil {
- if propertyErr, ok := err.(*proptools.ExtendPropertyError); ok {
- ctx.PropertyErrorf(propertyErr.Property, "%s", propertyErr.Err.Error())
- } else {
- panic(err)
- }
+ return err
}
}
}
+
+ return nil
}
func RegisterDefaultsPreArchMutators(ctx RegisterMutatorsContext) {
@@ -348,12 +609,12 @@
func defaultsMutator(ctx TopDownMutatorContext) {
if defaultable, ok := ctx.Module().(Defaultable); ok {
if len(defaultable.defaults().Defaults) > 0 {
- var defaultsList []Defaults
+ var defaultsList []DefaultsModule
seen := make(map[Defaults]bool)
ctx.WalkDeps(func(module, parent Module) bool {
if ctx.OtherModuleDependencyTag(module) == DefaultsDepTag {
- if defaults, ok := module.(Defaults); ok {
+ if defaults, ok := module.(DefaultsModule); ok {
if !seen[defaults] {
seen[defaults] = true
defaultsList = append(defaultsList, defaults)
diff --git a/android/defaults_test.go b/android/defaults_test.go
index a7542ab..d80f40c 100644
--- a/android/defaults_test.go
+++ b/android/defaults_test.go
@@ -19,7 +19,14 @@
)
type defaultsTestProperties struct {
- Foo []string
+ Foo []string
+ Bar []string
+ Nested struct {
+ Fizz *bool
+ }
+ Other struct {
+ Buzz *string
+ }
}
type defaultsTestModule struct {
@@ -130,3 +137,167 @@
// TODO: missing transitive defaults is currently not handled
_ = missingTransitiveDefaults
}
+
+func TestProtectedProperties_ProtectedPropertyNotSet(t *testing.T) {
+ bp := `
+ defaults {
+ name: "transitive",
+ protected_properties: ["foo"],
+ }
+ `
+
+ GroupFixturePreparers(
+ prepareForDefaultsTest,
+ FixtureWithRootAndroidBp(bp),
+ ).ExtendWithErrorHandler(FixtureExpectsAtLeastOneErrorMatchingPattern(
+ "module \"transitive\": foo: is not set; protected properties must be explicitly set")).
+ RunTest(t)
+}
+
+func TestProtectedProperties_ProtectedPropertyNotLeaf(t *testing.T) {
+ bp := `
+ defaults {
+ name: "transitive",
+ protected_properties: ["nested"],
+ nested: {
+ fizz: true,
+ },
+ }
+ `
+
+ GroupFixturePreparers(
+ prepareForDefaultsTest,
+ FixtureWithRootAndroidBp(bp),
+ ).ExtendWithErrorHandler(FixtureExpectsAtLeastOneErrorMatchingPattern(
+ `\Qmodule "transitive": nested: property is not supported by this module type "defaults"\E`)).
+ RunTest(t)
+}
+
+// TestProtectedProperties_ApplyDefaults makes sure that the protected_properties property has
+// defaults applied.
+func TestProtectedProperties_HasDefaultsApplied(t *testing.T) {
+
+ bp := `
+ defaults {
+ name: "transitive",
+ protected_properties: ["foo"],
+ foo: ["transitive"],
+ }
+
+ defaults {
+ name: "defaults",
+ defaults: ["transitive"],
+ protected_properties: ["bar"],
+ bar: ["defaults"],
+ }
+ `
+
+ result := GroupFixturePreparers(
+ prepareForDefaultsTest,
+ FixtureWithRootAndroidBp(bp),
+ ).RunTest(t)
+
+ defaults := result.Module("defaults", "").(DefaultsModule)
+ AssertDeepEquals(t, "defaults protected properties", []string{"foo", "bar"}, defaults.protectedProperties())
+}
+
+// TestProtectedProperties_ProtectAllProperties makes sure that protected_properties: ["*"] protects
+// all properties.
+func TestProtectedProperties_ProtectAllProperties(t *testing.T) {
+
+ bp := `
+ defaults {
+ name: "transitive",
+ protected_properties: ["other.buzz"],
+ other: {
+ buzz: "transitive",
+ },
+ }
+
+ defaults {
+ name: "defaults",
+ defaults: ["transitive"],
+ visibility: ["//visibility:private"],
+ protected_properties: ["*"],
+ foo: ["other"],
+ bar: ["defaults"],
+ nested: {
+ fizz: true,
+ }
+ }
+ `
+
+ result := GroupFixturePreparers(
+ prepareForDefaultsTest,
+ FixtureWithRootAndroidBp(bp),
+ ).RunTest(t)
+
+ defaults := result.Module("defaults", "").(DefaultsModule)
+ AssertDeepEquals(t, "defaults protected properties", []string{"other.buzz", "bar", "foo", "nested.fizz"},
+ defaults.protectedProperties())
+}
+
+func TestProtectedProperties_DetectedOverride(t *testing.T) {
+ bp := `
+ defaults {
+ name: "defaults",
+ protected_properties: ["foo", "nested.fizz"],
+ foo: ["defaults"],
+ nested: {
+ fizz: true,
+ },
+ }
+
+ test {
+ name: "foo",
+ defaults: ["defaults"],
+ foo: ["module"],
+ nested: {
+ fizz: false,
+ },
+ }
+ `
+
+ GroupFixturePreparers(
+ prepareForDefaultsTest,
+ FixtureWithRootAndroidBp(bp),
+ ).ExtendWithErrorHandler(FixtureExpectsAllErrorsToMatchAPattern(
+ []string{
+ `\Qmodule "foo": attempts to append ["module"] to protected property "foo"'s value of ["defaults"] defined in module "defaults"\E`,
+ `\Qmodule "foo": attempts to override protected property "nested.fizz" defined in module "defaults" with a different value (override true with false) so removing the property may necessitate other changes.\E`,
+ })).RunTest(t)
+}
+
+func TestProtectedProperties_DefaultsConflict(t *testing.T) {
+ bp := `
+ defaults {
+ name: "defaults1",
+ protected_properties: ["other.buzz"],
+ other: {
+ buzz: "value",
+ },
+ }
+
+ defaults {
+ name: "defaults2",
+ protected_properties: ["other.buzz"],
+ other: {
+ buzz: "another",
+ },
+ }
+
+ test {
+ name: "foo",
+ defaults: ["defaults1", "defaults2"],
+ }
+ `
+
+ GroupFixturePreparers(
+ prepareForDefaultsTest,
+ FixtureWithRootAndroidBp(bp),
+ ).ExtendWithErrorHandler(FixtureExpectsAtLeastOneErrorMatchingPattern(
+ `\Qmodule "foo": has conflicting default values for protected property "other.buzz":
+ defaults module "defaults1" provides value "value"
+ defaults module "defaults2" provides value "another"\E`,
+ )).RunTest(t)
+}
diff --git a/android/mutator.go b/android/mutator.go
index 7f93baf..9e4aa59 100644
--- a/android/mutator.go
+++ b/android/mutator.go
@@ -440,6 +440,64 @@
// reached
DepTag() blueprint.DependencyTag
}
+
+// Transition mutators implement a top-down mechanism where a module tells its
+// direct dependencies what variation they should be built in but the dependency
+// has the final say.
+//
+// When implementing a transition mutator, one needs to implement four methods:
+// - Split() that tells what variations a module has by itself
+// - OutgoingTransition() where a module tells what it wants from its
+// dependency
+// - IncomingTransition() where a module has the final say about its own
+// variation
+// - Mutate() that changes the state of a module depending on its variation
+//
+// That the effective variation of module B when depended on by module A is the
+// composition the outgoing transition of module A and the incoming transition
+// of module B.
+//
+// the outgoing transition should not take the properties of the dependency into
+// account, only those of the module that depends on it. For this reason, the
+// dependency is not even passed into it as an argument. Likewise, the incoming
+// transition should not take the properties of the depending module into
+// account and is thus not informed about it. This makes for a nice
+// decomposition of the decision logic.
+//
+// A given transition mutator only affects its own variation; other variations
+// stay unchanged along the dependency edges.
+//
+// Soong makes sure that all modules are created in the desired variations and
+// that dependency edges are set up correctly. This ensures that "missing
+// variation" errors do not happen and allows for more flexible changes in the
+// value of the variation among dependency edges (as oppposed to bottom-up
+// mutators where if module A in variation X depends on module B and module B
+// has that variation X, A must depend on variation X of B)
+//
+// The limited power of the context objects passed to individual mutators
+// methods also makes it more difficult to shoot oneself in the foot. Complete
+// safety is not guaranteed because no one prevents individual transition
+// mutators from mutating modules in illegal ways and for e.g. Split() or
+// Mutate() to run their own visitations of the transitive dependency of the
+// module and both of these are bad ideas, but it's better than no guardrails at
+// all.
+//
+// This model is pretty close to Bazel's configuration transitions. The mapping
+// between concepts in Soong and Bazel is as follows:
+// - Module == configured target
+// - Variant == configuration
+// - Variation name == configuration flag
+// - Variation == configuration flag value
+// - Outgoing transition == attribute transition
+// - Incoming transition == rule transition
+//
+// The Split() method does not have a Bazel equivalent and Bazel split
+// transitions do not have a Soong equivalent.
+//
+// Mutate() does not make sense in Bazel due to the different models of the
+// two systems: when creating new variations, Soong clones the old module and
+// thus some way is needed to change it state whereas Bazel creates each
+// configuration of a given configured target anew.
type TransitionMutator interface {
// Split returns the set of variations that should be created for a module no
// matter who depends on it. Used when Make depends on a particular variation
@@ -448,7 +506,7 @@
// called on.
Split(ctx BaseModuleContext) []string
- // OutCalled on a module to determine which variation it wants from its direct
+ // Called on a module to determine which variation it wants from its direct
// dependencies. The dependency itself can override this decision. This method
// should not mutate the module itself.
OutgoingTransition(ctx OutgoingTransitionContext, sourceVariation string) string
diff --git a/android/paths.go b/android/paths.go
index e0e5ae5..d5cec9a 100644
--- a/android/paths.go
+++ b/android/paths.go
@@ -1739,10 +1739,16 @@
partionPaths = []string{"target", "product", ctx.Config().DeviceName(), partition}
} else {
osName := os.String()
- if os == Linux || os == LinuxMusl {
+ if os == Linux {
// instead of linux_glibc
osName = "linux"
}
+ if os == LinuxMusl && ctx.Config().UseHostMusl() {
+ // When using musl instead of glibc, use "linux" instead of "linux_musl". When cross
+ // compiling we will still use "linux_musl".
+ osName = "linux"
+ }
+
// SOONG_HOST_OUT is set to out/host/$(HOST_OS)-$(HOST_PREBUILT_ARCH)
// and HOST_PREBUILT_ARCH is forcibly set to x86 even on x86_64 hosts. We don't seem
// to have a plan to fix it (see the comment in build/make/core/envsetup.mk).
diff --git a/android/variable.go b/android/variable.go
index 734ed1b..50fc304 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -429,6 +429,7 @@
ShippingApiLevel *string `json:",omitempty"`
+ BuildBrokenDepfile *bool `json:",omitempty"`
BuildBrokenEnforceSyspropOwner bool `json:",omitempty"`
BuildBrokenTrebleSyspropNeverallow bool `json:",omitempty"`
BuildBrokenVendorPropertyNamespace bool `json:",omitempty"`
diff --git a/bazel/aquery_test.go b/bazel/aquery_test.go
index cf51b39..1da6340 100644
--- a/bazel/aquery_test.go
+++ b/bazel/aquery_test.go
@@ -17,6 +17,7 @@
import (
"fmt"
"reflect"
+ "sort"
"testing"
)
@@ -897,7 +898,7 @@
func assertFlattenedDepsets(t *testing.T, actualDepsets []AqueryDepset, expectedDepsetFiles [][]string) {
t.Helper()
if len(actualDepsets) != len(expectedDepsetFiles) {
- t.Errorf("Expected %s depsets, but got %s depsets", expectedDepsetFiles, actualDepsets)
+ t.Errorf("Expected %d depsets, but got %d depsets", len(expectedDepsetFiles), len(actualDepsets))
}
for i, actualDepset := range actualDepsets {
actualFlattenedInputs := flattenDepsets([]string{actualDepset.ContentHash}, actualDepsets)
@@ -1484,50 +1485,54 @@
len(expected), len(actual), expected, actual)
return
}
-ACTUAL_LOOP:
- for _, actualStatement := range actual {
- for _, expectedStatement := range expected {
- if buildStatementEquals(actualStatement, expectedStatement) {
- continue ACTUAL_LOOP
- }
+ type compareFn = func(i int, j int) bool
+ byCommand := func(slice []BuildStatement) compareFn {
+ return func(i int, j int) bool {
+ return slice[i].Command < slice[j].Command
}
- t.Errorf("unexpected build statement %#v.\n expected: %#v",
- actualStatement, expected)
- return
+ }
+ sort.SliceStable(expected, byCommand(expected))
+ sort.SliceStable(actual, byCommand(actual))
+ for i, actualStatement := range actual {
+ expectedStatement := expected[i]
+ if differingField := buildStatementEquals(actualStatement, expectedStatement); differingField != "" {
+ t.Errorf("%s differs\nunexpected build statement %#v.\nexpected: %#v",
+ differingField, actualStatement, expected)
+ return
+ }
}
}
-func buildStatementEquals(first BuildStatement, second BuildStatement) bool {
+func buildStatementEquals(first BuildStatement, second BuildStatement) string {
if first.Mnemonic != second.Mnemonic {
- return false
+ return "Mnemonic"
}
if first.Command != second.Command {
- return false
+ return "Command"
}
// Ordering is significant for environment variables.
if !reflect.DeepEqual(first.Env, second.Env) {
- return false
+ return "Env"
}
// Ordering is irrelevant for input and output paths, so compare sets.
- if !reflect.DeepEqual(stringSet(first.InputPaths), stringSet(second.InputPaths)) {
- return false
+ if !reflect.DeepEqual(sortedStrings(first.InputPaths), sortedStrings(second.InputPaths)) {
+ return "InputPaths"
}
- if !reflect.DeepEqual(stringSet(first.OutputPaths), stringSet(second.OutputPaths)) {
- return false
+ if !reflect.DeepEqual(sortedStrings(first.OutputPaths), sortedStrings(second.OutputPaths)) {
+ return "OutputPaths"
}
- if !reflect.DeepEqual(stringSet(first.SymlinkPaths), stringSet(second.SymlinkPaths)) {
- return false
+ if !reflect.DeepEqual(sortedStrings(first.SymlinkPaths), sortedStrings(second.SymlinkPaths)) {
+ return "SymlinkPaths"
}
if first.Depfile != second.Depfile {
- return false
+ return "Depfile"
}
- return true
+ return ""
}
-func stringSet(stringSlice []string) map[string]struct{} {
- stringMap := make(map[string]struct{})
- for _, s := range stringSlice {
- stringMap[s] = struct{}{}
- }
- return stringMap
+func sortedStrings(stringSlice []string) []string {
+ sorted := make([]string, len(stringSlice))
+ copy(sorted, stringSlice)
+ sort.Strings(sorted)
+ return sorted
}
diff --git a/bazel/configurability.go b/bazel/configurability.go
index 7355ac7..0ab49eb 100644
--- a/bazel/configurability.go
+++ b/bazel/configurability.go
@@ -43,6 +43,8 @@
osArchDarwinX86_64 = "darwin_x86_64"
osArchLinuxX86 = "linux_glibc_x86"
osArchLinuxX86_64 = "linux_glibc_x86_64"
+ osArchLinuxMuslArm = "linux_musl_arm"
+ osArchLinuxMuslArm64 = "linux_musl_arm64"
osArchLinuxMuslX86 = "linux_musl_x86"
osArchLinuxMuslX86_64 = "linux_musl_x86_64"
osArchLinuxBionicArm64 = "linux_bionic_arm64"
@@ -101,6 +103,8 @@
osArchDarwinX86_64: "//build/bazel/platforms/os_arch:darwin_x86_64",
osArchLinuxX86: "//build/bazel/platforms/os_arch:linux_glibc_x86",
osArchLinuxX86_64: "//build/bazel/platforms/os_arch:linux_glibc_x86_64",
+ osArchLinuxMuslArm: "//build/bazel/platforms/os_arch:linux_musl_arm",
+ osArchLinuxMuslArm64: "//build/bazel/platforms/os_arch:linux_musl_arm64",
osArchLinuxMuslX86: "//build/bazel/platforms/os_arch:linux_musl_x86",
osArchLinuxMuslX86_64: "//build/bazel/platforms/os_arch:linux_musl_x86_64",
osArchLinuxBionicArm64: "//build/bazel/platforms/os_arch:linux_bionic_arm64",
diff --git a/bp2build/cc_object_conversion_test.go b/bp2build/cc_object_conversion_test.go
index ea58086..52688d9 100644
--- a/bp2build/cc_object_conversion_test.go
+++ b/bp2build/cc_object_conversion_test.go
@@ -414,6 +414,7 @@
"bionic_arm64.cpp",
],
"//build/bazel/platforms/os_arch:linux_glibc_x86": ["linux_x86.cpp"],
+ "//build/bazel/platforms/os_arch:linux_musl_arm64": ["linux_arm64.cpp"],
"//build/bazel/platforms/os_arch:linux_musl_x86": ["linux_x86.cpp"],
"//conditions:default": [],
})`,
diff --git a/cc/cc_test.go b/cc/cc_test.go
index 9430434..b6d196c 100644
--- a/cc/cc_test.go
+++ b/cc/cc_test.go
@@ -4095,7 +4095,7 @@
{
name: "assemble",
src: "foo.s",
- expected: combineSlices(baseExpectedFlags, []string{"-D__ASSEMBLY__", "-fdebug-default-version=4"}, expectedIncludes, lastIncludes),
+ expected: combineSlices(baseExpectedFlags, []string{"${config.CommonGlobalAsflags}"}, expectedIncludes, lastIncludes),
},
}
diff --git a/cc/compiler.go b/cc/compiler.go
index 72797eb..3c904b8 100644
--- a/cc/compiler.go
+++ b/cc/compiler.go
@@ -494,11 +494,7 @@
}
}
- flags.Global.AsFlags = append(flags.Global.AsFlags, "-D__ASSEMBLY__")
-
- // TODO(b/235105792): override global -fdebug-default-version=5, it is causing $TMPDIR to
- // end up in the dwarf data for crtend_so.S.
- flags.Global.AsFlags = append(flags.Global.AsFlags, "-fdebug-default-version=4")
+ flags.Global.AsFlags = append(flags.Global.AsFlags, "${config.CommonGlobalAsflags}")
flags.Global.CppFlags = append(flags.Global.CppFlags, tc.Cppflags())
diff --git a/cc/config/Android.bp b/cc/config/Android.bp
index 1a21c13..64a121e 100644
--- a/cc/config/Android.bp
+++ b/cc/config/Android.bp
@@ -24,6 +24,7 @@
"x86_device.go",
"x86_64_device.go",
+ "arm_linux_host.go",
"darwin_host.go",
"x86_linux_host.go",
"x86_linux_bionic_host.go",
diff --git a/cc/config/arm64_linux_host.go b/cc/config/arm64_linux_host.go
index 5c7f926..2d316e6 100644
--- a/cc/config/arm64_linux_host.go
+++ b/cc/config/arm64_linux_host.go
@@ -64,25 +64,25 @@
// toolchain config for ARM64 Linux CrossHost. Almost everything is the same as the ARM64 Android
// target. The overridden methods below show the differences.
-type toolchainLinuxArm64 struct {
+type toolchainLinuxBionicArm64 struct {
toolchainArm64
}
-func (toolchainLinuxArm64) ClangTriple() string {
+func (toolchainLinuxBionicArm64) ClangTriple() string {
// Note the absence of "-android" suffix. The compiler won't define __ANDROID__
return "aarch64-linux"
}
-func (toolchainLinuxArm64) Cflags() string {
+func (toolchainLinuxBionicArm64) Cflags() string {
// The inherited flags + extra flags
return "${config.Arm64Cflags} ${config.LinuxBionicArm64Cflags}"
}
-func (toolchainLinuxArm64) CrtBeginSharedBinary() []string {
+func (toolchainLinuxBionicArm64) CrtBeginSharedBinary() []string {
return linuxArm64CrtBeginSharedBinary
}
-func linuxArm64ToolchainFactory(arch android.Arch) Toolchain {
+func linuxBionicArm64ToolchainFactory(arch android.Arch) Toolchain {
archVariant := "armv8-a" // for host, default to armv8-a
toolchainCflags := []string{arm64ArchVariantCflagsVar[archVariant]}
@@ -90,7 +90,7 @@
// the host CPU needs the fix
extraLdflags := "-Wl,--fix-cortex-a53-843419"
- ret := toolchainLinuxArm64{}
+ ret := toolchainLinuxBionicArm64{}
// add the extra ld and lld flags
ret.toolchainArm64.ldflags = strings.Join([]string{
@@ -108,5 +108,5 @@
}
func init() {
- registerToolchainFactory(android.LinuxBionic, android.Arm64, linuxArm64ToolchainFactory)
+ registerToolchainFactory(android.LinuxBionic, android.Arm64, linuxBionicArm64ToolchainFactory)
}
diff --git a/cc/config/arm_linux_host.go b/cc/config/arm_linux_host.go
new file mode 100644
index 0000000..525fb5d
--- /dev/null
+++ b/cc/config/arm_linux_host.go
@@ -0,0 +1,174 @@
+// Copyright 2022 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package config
+
+import "android/soong/android"
+
+var (
+ linuxArmCflags = []string{
+ "-march=armv7a",
+ }
+
+ linuxArm64Cflags = []string{}
+
+ linuxArmLdflags = []string{
+ "-march=armv7a",
+ }
+
+ linuxArm64Ldflags = []string{}
+)
+
+func init() {
+ exportedVars.ExportStringListStaticVariable("LinuxArmCflags", linuxArmCflags)
+ exportedVars.ExportStringListStaticVariable("LinuxArm64Cflags", linuxArm64Cflags)
+ exportedVars.ExportStringListStaticVariable("LinuxArmLdflags", linuxArmLdflags)
+ exportedVars.ExportStringListStaticVariable("LinuxArmLldflags", linuxArmLdflags)
+ exportedVars.ExportStringListStaticVariable("LinuxArm64Ldflags", linuxArm64Ldflags)
+ exportedVars.ExportStringListStaticVariable("LinuxArm64Lldflags", linuxArm64Ldflags)
+
+ exportedVars.ExportStringListStaticVariable("LinuxArmYasmFlags", []string{"-f elf32 -m arm"})
+ exportedVars.ExportStringListStaticVariable("LinuxArm64YasmFlags", []string{"-f elf64 -m aarch64"})
+
+}
+
+// Musl arm+arm64
+type toolchainLinuxArm struct {
+ toolchain32Bit
+ toolchainLinux
+}
+
+type toolchainLinuxArm64 struct {
+ toolchain64Bit
+ toolchainLinux
+}
+
+func (t *toolchainLinuxArm) Name() string {
+ return "arm"
+}
+
+func (t *toolchainLinuxArm64) Name() string {
+ return "arm64"
+}
+
+func (t *toolchainLinuxArm) Cflags() string {
+ return "${config.LinuxCflags} ${config.LinuxArmCflags}"
+}
+
+func (t *toolchainLinuxArm) Cppflags() string {
+ return ""
+}
+
+func (t *toolchainLinuxArm64) Cflags() string {
+ return "${config.LinuxCflags} ${config.LinuxArm64Cflags}"
+}
+
+func (t *toolchainLinuxArm64) Cppflags() string {
+ return ""
+}
+
+func (t *toolchainLinuxArm) Ldflags() string {
+ return "${config.LinuxLdflags} ${config.LinuxArmLdflags}"
+}
+
+func (t *toolchainLinuxArm) Lldflags() string {
+ return "${config.LinuxLldflags} ${config.LinuxArmLldflags}"
+}
+
+func (t *toolchainLinuxArm64) Ldflags() string {
+ return "${config.LinuxLdflags} ${config.LinuxArm64Ldflags}"
+}
+
+func (t *toolchainLinuxArm64) Lldflags() string {
+ return "${config.LinuxLldflags} ${config.LinuxArm64Lldflags}"
+}
+
+func (t *toolchainLinuxArm) YasmFlags() string {
+ return "${config.LinuxArmYasmFlags}"
+}
+
+func (t *toolchainLinuxArm64) YasmFlags() string {
+ return "${config.LinuxArm64YasmFlags}"
+}
+
+func (toolchainLinuxArm) LibclangRuntimeLibraryArch() string {
+ return "arm"
+}
+
+func (toolchainLinuxArm64) LibclangRuntimeLibraryArch() string {
+ return "arm64"
+}
+
+func (t *toolchainLinuxArm) InstructionSetFlags(isa string) (string, error) {
+ // TODO: Is no thumb OK?
+ return t.toolchainBase.InstructionSetFlags("")
+}
+
+type toolchainLinuxMuslArm struct {
+ toolchainLinuxArm
+ toolchainMusl
+}
+
+type toolchainLinuxMuslArm64 struct {
+ toolchainLinuxArm64
+ toolchainMusl
+}
+
+func (t *toolchainLinuxMuslArm) ClangTriple() string {
+ return "arm-linux-musleabihf"
+}
+
+func (t *toolchainLinuxMuslArm) Cflags() string {
+ return t.toolchainLinuxArm.Cflags() + " " + t.toolchainMusl.Cflags()
+}
+
+func (t *toolchainLinuxMuslArm) Ldflags() string {
+ return t.toolchainLinuxArm.Ldflags() + " " + t.toolchainMusl.Ldflags()
+}
+
+func (t *toolchainLinuxMuslArm) Lldflags() string {
+ return t.toolchainLinuxArm.Lldflags() + " " + t.toolchainMusl.Lldflags()
+}
+
+func (t *toolchainLinuxMuslArm64) ClangTriple() string {
+ return "aarch64-linux-musl"
+}
+
+func (t *toolchainLinuxMuslArm64) Cflags() string {
+ return t.toolchainLinuxArm64.Cflags() + " " + t.toolchainMusl.Cflags()
+}
+
+func (t *toolchainLinuxMuslArm64) Ldflags() string {
+ return t.toolchainLinuxArm64.Ldflags() + " " + t.toolchainMusl.Ldflags()
+}
+
+func (t *toolchainLinuxMuslArm64) Lldflags() string {
+ return t.toolchainLinuxArm64.Lldflags() + " " + t.toolchainMusl.Lldflags()
+}
+
+var toolchainLinuxMuslArmSingleton Toolchain = &toolchainLinuxMuslArm{}
+var toolchainLinuxMuslArm64Singleton Toolchain = &toolchainLinuxMuslArm64{}
+
+func linuxMuslArmToolchainFactory(arch android.Arch) Toolchain {
+ return toolchainLinuxMuslArmSingleton
+}
+
+func linuxMuslArm64ToolchainFactory(arch android.Arch) Toolchain {
+ return toolchainLinuxMuslArm64Singleton
+}
+
+func init() {
+ registerToolchainFactory(android.LinuxMusl, android.Arm, linuxMuslArmToolchainFactory)
+ registerToolchainFactory(android.LinuxMusl, android.Arm64, linuxMuslArm64ToolchainFactory)
+}
diff --git a/cc/config/global.go b/cc/config/global.go
index b09598a..c5fde55 100644
--- a/cc/config/global.go
+++ b/cc/config/global.go
@@ -117,6 +117,13 @@
commonGlobalConlyflags = []string{}
+ commonGlobalAsflags = []string{
+ "-D__ASSEMBLY__",
+ // TODO(b/235105792): override global -fdebug-default-version=5, it is causing $TMPDIR to
+ // end up in the dwarf data for crtend_so.S.
+ "-fdebug-default-version=4",
+ }
+
deviceGlobalCflags = []string{
"-ffunction-sections",
"-fdata-sections",
@@ -313,6 +320,7 @@
}
exportedVars.ExportStringListStaticVariable("CommonGlobalConlyflags", commonGlobalConlyflags)
+ exportedVars.ExportStringListStaticVariable("CommonGlobalAsflags", commonGlobalAsflags)
exportedVars.ExportStringListStaticVariable("DeviceGlobalCppflags", deviceGlobalCppflags)
exportedVars.ExportStringListStaticVariable("DeviceGlobalLdflags", deviceGlobalLdflags)
exportedVars.ExportStringListStaticVariable("DeviceGlobalLldflags", deviceGlobalLldflags)
diff --git a/cc/library.go b/cc/library.go
index 0fa01d7..c445a42 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -925,7 +925,6 @@
if ctx.Darwin() {
f = append(f,
"-dynamiclib",
- "-single_module",
"-install_name @rpath/"+libName+flags.Toolchain.ShlibSuffix(),
)
if ctx.Arch().ArchType == android.X86 {
diff --git a/cc/linkable.go b/cc/linkable.go
index c58bfdf..2316d86 100644
--- a/cc/linkable.go
+++ b/cc/linkable.go
@@ -106,6 +106,9 @@
UnstrippedOutputFile() android.Path
CoverageFiles() android.Paths
+ // CoverageOutputFile returns the output archive of gcno coverage information files.
+ CoverageOutputFile() android.OptionalPath
+
NonCcVariants() bool
SelectedStl() string
@@ -133,6 +136,12 @@
UseSdk() bool
+ // IsNdk returns true if the library is in the configs known NDK list.
+ IsNdk(config android.Config) bool
+
+ // IsStubs returns true if the this is a stubs library.
+ IsStubs() bool
+
// IsLlndk returns true for both LLNDK (public) and LLNDK-private libs.
IsLlndk() bool
diff --git a/cc/linker.go b/cc/linker.go
index 78d2d41..76a60ca 100644
--- a/cc/linker.go
+++ b/cc/linker.go
@@ -436,11 +436,6 @@
}
func (linker *baseLinker) useClangLld(ctx ModuleContext) bool {
- // Clang lld is not ready for for Darwin host executables yet.
- // See https://lld.llvm.org/AtomLLD.html for status of lld for Mach-O.
- if ctx.Darwin() {
- return false
- }
if linker.Properties.Use_clang_lld != nil {
return Bool(linker.Properties.Use_clang_lld)
}
diff --git a/cc/sanitize.go b/cc/sanitize.go
index e0779c6..92987f7 100644
--- a/cc/sanitize.go
+++ b/cc/sanitize.go
@@ -715,10 +715,6 @@
flags.Local.CFlags = append(flags.Local.CFlags, "-fno-sanitize=vptr,function")
}
- if enableMinimalRuntime(sanitize) {
- flags.Local.CFlags = append(flags.Local.CFlags, strings.Join(minimalRuntimeFlags, " "))
- }
-
if Bool(sanitize.Properties.Sanitize.Fuzzer) {
// When fuzzing, we wish to crash with diagnostics on any bug.
flags.Local.CFlags = append(flags.Local.CFlags, "-fno-sanitize-trap=all", "-fno-sanitize-recover=all")
@@ -727,6 +723,11 @@
} else {
flags.Local.CFlags = append(flags.Local.CFlags, "-fsanitize-trap=all", "-ftrap-function=abort")
}
+
+ if enableMinimalRuntime(sanitize) {
+ flags.Local.CFlags = append(flags.Local.CFlags, strings.Join(minimalRuntimeFlags, " "))
+ }
+
// http://b/119329758, Android core does not boot up with this sanitizer yet.
if toDisableImplicitIntegerChange(flags.Local.CFlags) {
flags.Local.CFlags = append(flags.Local.CFlags, "-fno-sanitize=implicit-integer-sign-change")
diff --git a/genrule/genrule.go b/genrule/genrule.go
index 2a80563..b796877 100644
--- a/genrule/genrule.go
+++ b/genrule/genrule.go
@@ -590,6 +590,18 @@
}
func (g *Module) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+ // Allowlist genrule to use depfile until we have a solution to remove it.
+ // TODO(b/235582219): Remove allowlist for genrule
+ if ctx.ModuleType() == "gensrcs" &&
+ !ctx.DeviceConfig().BuildBrokenDepfile() &&
+ Bool(g.properties.Depfile) {
+ ctx.PropertyErrorf(
+ "depfile",
+ "Deprecated to ensure the module type is convertible to Bazel. "+
+ "Try specifying the dependencies explicitly so that there is no need to use depfile. "+
+ "If not possible, the escape hatch is to use BUILD_BROKEN_DEPFILE to bypass the error.")
+ }
+
g.generateCommonBuildActions(ctx)
// For <= 6 outputs, just embed those directly in the users. Right now, that covers >90% of
diff --git a/genrule/genrule_test.go b/genrule/genrule_test.go
index 1b5cef2..b9be1f7 100644
--- a/genrule/genrule_test.go
+++ b/genrule/genrule_test.go
@@ -15,6 +15,7 @@
package genrule
import (
+ "fmt"
"os"
"regexp"
"testing"
@@ -626,6 +627,73 @@
}
}
+func TestGensrcsBuildBrokenDepfile(t *testing.T) {
+ tests := []struct {
+ name string
+ prop string
+ BuildBrokenDepfile *bool
+ err string
+ }{
+ {
+ name: `error when BuildBrokenDepfile is set to false`,
+ prop: `
+ depfile: true,
+ cmd: "cat $(in) > $(out) && cat $(depfile)",
+ `,
+ BuildBrokenDepfile: proptools.BoolPtr(false),
+ err: "depfile: Deprecated to ensure the module type is convertible to Bazel",
+ },
+ {
+ name: `error when BuildBrokenDepfile is not set`,
+ prop: `
+ depfile: true,
+ cmd: "cat $(in) > $(out) && cat $(depfile)",
+ `,
+ err: "depfile: Deprecated to ensure the module type is convertible to Bazel.",
+ },
+ {
+ name: `no error when BuildBrokenDepfile is explicitly set to true`,
+ prop: `
+ depfile: true,
+ cmd: "cat $(in) > $(out) && cat $(depfile)",
+ `,
+ BuildBrokenDepfile: proptools.BoolPtr(true),
+ },
+ {
+ name: `no error if depfile is not set`,
+ prop: `
+ cmd: "cat $(in) > $(out)",
+ `,
+ },
+ }
+ for _, test := range tests {
+ t.Run(test.name, func(t *testing.T) {
+ bp := fmt.Sprintf(`
+ gensrcs {
+ name: "foo",
+ srcs: ["data.txt"],
+ %s
+ }`, test.prop)
+
+ var expectedErrors []string
+ if test.err != "" {
+ expectedErrors = append(expectedErrors, test.err)
+ }
+ android.GroupFixturePreparers(
+ prepareForGenRuleTest,
+ android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+ if test.BuildBrokenDepfile != nil {
+ variables.BuildBrokenDepfile = test.BuildBrokenDepfile
+ }
+ }),
+ ).
+ ExtendWithErrorHandler(android.FixtureExpectsAllErrorsToMatchAPattern(expectedErrors)).
+ RunTestWithBp(t, bp)
+ })
+
+ }
+}
+
func TestGenruleDefaults(t *testing.T) {
bp := `
genrule_defaults {
diff --git a/java/app.go b/java/app.go
index c5d88e9..23a9816 100755
--- a/java/app.go
+++ b/java/app.go
@@ -583,6 +583,16 @@
a.classLoaderContexts = a.usesLibrary.classLoaderContextForUsesLibDeps(ctx)
+ var noticeAssetPath android.WritablePath
+ if Bool(a.appProperties.Embed_notices) || ctx.Config().IsEnvTrue("ALWAYS_EMBED_NOTICES") {
+ // The rule to create the notice file can't be generated yet, as the final output path
+ // for the apk isn't known yet. Add the path where the notice file will be generated to the
+ // aapt rules now before calling aaptBuildActions, the rule to create the notice file will
+ // be generated later.
+ noticeAssetPath = android.PathForModuleOut(ctx, "NOTICE", "NOTICE.html.gz")
+ a.aapt.noticeFile = android.OptionalPathForPath(noticeAssetPath)
+ }
+
// Process all building blocks, from AAPT to certificates.
a.aaptBuildActions(ctx)
@@ -654,7 +664,8 @@
a.extraOutputFiles = append(a.extraOutputFiles, v4SignatureFile)
}
- if Bool(a.appProperties.Embed_notices) || ctx.Config().IsEnvTrue("ALWAYS_EMBED_NOTICES") {
+ if a.aapt.noticeFile.Valid() {
+ // Generating the notice file rule has to be here after a.outputFile is known.
noticeFile := android.PathForModuleOut(ctx, "NOTICE.html.gz")
android.BuildNoticeHtmlOutputFromLicenseMetadata(
ctx, noticeFile, "", "",
@@ -663,13 +674,11 @@
android.PathForModuleInstall(ctx).String() + "/",
a.outputFile.String(),
})
- noticeAssetPath := android.PathForModuleOut(ctx, "NOTICE", "NOTICE.html.gz")
builder := android.NewRuleBuilder(pctx, ctx)
builder.Command().Text("cp").
Input(noticeFile).
Output(noticeAssetPath)
builder.Build("notice_dir", "Building notice dir")
- a.aapt.noticeFile = android.OptionalPathForPath(noticeAssetPath)
}
for _, split := range a.aapt.splits {
@@ -731,7 +740,7 @@
tag := ctx.OtherModuleDependencyTag(module)
if IsJniDepTag(tag) || cc.IsSharedDepTag(tag) {
- if dep, ok := module.(*cc.Module); ok {
+ if dep, ok := module.(cc.LinkableInterface); ok {
if dep.IsNdk(ctx.Config()) || dep.IsStubs() {
return false
}
diff --git a/java/config/config.go b/java/config/config.go
index e728b7d..1d4b242 100644
--- a/java/config/config.go
+++ b/java/config/config.go
@@ -159,7 +159,7 @@
pctx.HostBinToolVariable("ZipSyncCmd", "zipsync")
pctx.HostBinToolVariable("ApiCheckCmd", "apicheck")
pctx.HostBinToolVariable("D8Cmd", "d8")
- pctx.HostBinToolVariable("R8Cmd", "r8-compat-proguard")
+ pctx.HostBinToolVariable("R8Cmd", "r8")
pctx.HostBinToolVariable("HiddenAPICmd", "hiddenapi")
pctx.HostBinToolVariable("ExtractApksCmd", "extract_apks")
pctx.VariableFunc("TurbineJar", func(ctx android.PackageVarContext) string {
@@ -177,7 +177,7 @@
pctx.HostJavaToolVariable("MetalavaJar", "metalava.jar")
pctx.HostJavaToolVariable("DokkaJar", "dokka.jar")
pctx.HostJavaToolVariable("JetifierJar", "jetifier.jar")
- pctx.HostJavaToolVariable("R8Jar", "r8-compat-proguard.jar")
+ pctx.HostJavaToolVariable("R8Jar", "r8.jar")
pctx.HostJavaToolVariable("D8Jar", "d8.jar")
pctx.HostBinToolVariable("SoongJavacWrapper", "soong_javac_wrapper")
diff --git a/provenance/provenance_singleton.go b/provenance/provenance_singleton.go
index d1cbd8f..fbb6212 100644
--- a/provenance/provenance_singleton.go
+++ b/provenance/provenance_singleton.go
@@ -35,10 +35,10 @@
mergeProvenanceMetaData = pctx.AndroidStaticRule("mergeProvenanceMetaData",
blueprint.RuleParams{
- Command: `rm -rf $out $out.temp && ` +
+ Command: `rm -rf $out && ` +
`echo "# proto-file: build/soong/provenance/proto/provenance_metadata.proto" > $out && ` +
`echo "# proto-message: ProvenanceMetaDataList" >> $out && ` +
- `touch $out.temp && cat $out.temp $in | grep -v "^#.*" >> $out && rm -rf $out.temp`,
+ `for file in $in; do echo '' >> $out; echo 'metadata {' | cat - $$file | grep -Ev "^#.*|^$$" >> $out; echo '}' >> $out; done`,
})
)
diff --git a/rust/rust.go b/rust/rust.go
index 48419eb..d5d4929 100644
--- a/rust/rust.go
+++ b/rust/rust.go
@@ -695,6 +695,19 @@
panic(fmt.Errorf("CoverageFiles called on non-library module: %q", mod.BaseModuleName()))
}
+// Rust does not produce gcno files, and therefore does not produce a coverage archive.
+func (mod *Module) CoverageOutputFile() android.OptionalPath {
+ return android.OptionalPath{}
+}
+
+func (mod *Module) IsNdk(config android.Config) bool {
+ return false
+}
+
+func (mod *Module) IsStubs() bool {
+ return false
+}
+
func (mod *Module) installable(apexInfo android.ApexInfo) bool {
if !proptools.BoolDefault(mod.Installable(), mod.EverInstallable()) {
return false
diff --git a/ui/build/config.go b/ui/build/config.go
index 5765f21..59b01b3 100644
--- a/ui/build/config.go
+++ b/ui/build/config.go
@@ -211,7 +211,7 @@
}
if err := fetchEnvConfig(ctx, config, bc); err != nil {
- fmt.Fprintf(os.Stderr, "Failed to fetch config file: %v\n", err)
+ ctx.Verbosef("Failed to fetch config file: %v\n", err)
}
configDirs := []string{