Merge "Revert "Revert "Keep minimal abort when enabling integer overflow check"""
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/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/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/bazel/aquery_test.go b/bazel/aquery_test.go
index 8ba8b5a..1da6340 100644
--- a/bazel/aquery_test.go
+++ b/bazel/aquery_test.go
@@ -17,6 +17,7 @@
import (
"fmt"
"reflect"
+ "sort"
"testing"
)
@@ -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/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/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/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/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{