aboutsummaryrefslogtreecommitdiffstats
path: root/ui/build
diff options
context:
space:
mode:
Diffstat (limited to 'ui/build')
-rw-r--r--ui/build/Android.bp1
-rw-r--r--ui/build/build.go11
-rw-r--r--ui/build/config.go19
-rw-r--r--ui/build/test_build.go78
4 files changed, 101 insertions, 8 deletions
diff --git a/ui/build/Android.bp b/ui/build/Android.bp
index d1b49438..58098943 100644
--- a/ui/build/Android.bp
+++ b/ui/build/Android.bp
@@ -36,6 +36,7 @@ bootstrap_go_package {
"proc_sync.go",
"signal.go",
"soong.go",
+ "test_build.go",
"util.go",
],
testSrcs: [
diff --git a/ui/build/build.go b/ui/build/build.go
index 0df22b34..78eb6a32 100644
--- a/ui/build/build.go
+++ b/ui/build/build.go
@@ -68,6 +68,7 @@ const (
BuildSoong = 1 << iota
BuildKati = 1 << iota
BuildNinja = 1 << iota
+ RunBuildTests = 1 << iota
BuildAll = BuildProductConfig | BuildSoong | BuildKati | BuildNinja
)
@@ -172,14 +173,18 @@ func Build(ctx Context, config Config, what int) {
}
}
+ // Write combined ninja file
+ createCombinedBuildNinjaFile(ctx, config)
+
+ if what&RunBuildTests != 0 {
+ testForDanglingRules(ctx, config)
+ }
+
if what&BuildNinja != 0 {
if !config.SkipMake() {
installCleanIfNecessary(ctx, config)
}
- // Write combined ninja file
- createCombinedBuildNinjaFile(ctx, config)
-
// Run ninja
runNinja(ctx, config)
}
diff --git a/ui/build/config.go b/ui/build/config.go
index 940bb2fb..99ae2dac 100644
--- a/ui/build/config.go
+++ b/ui/build/config.go
@@ -34,11 +34,12 @@ type configImpl struct {
environ *Environment
// From the arguments
- parallel int
- keepGoing int
- verbose bool
- dist bool
- skipMake bool
+ parallel int
+ keepGoing int
+ verbose bool
+ checkbuild bool
+ dist bool
+ skipMake bool
// From the product config
katiArgs []string
@@ -206,6 +207,8 @@ func (c *configImpl) parseArgs(ctx Context, args []string) {
} else {
if arg == "dist" {
c.dist = true
+ } else if arg == "checkbuild" {
+ c.checkbuild = true
}
c.arguments = append(c.arguments, arg)
}
@@ -313,6 +316,12 @@ func (c *configImpl) KatiSuffix() string {
panic("SetKatiSuffix has not been called")
}
+// Checkbuild returns true if "checkbuild" was one of the build goals, which means that the
+// user is interested in additional checks at the expense of build time.
+func (c *configImpl) Checkbuild() bool {
+ return c.checkbuild
+}
+
func (c *configImpl) Dist() bool {
return c.dist
}
diff --git a/ui/build/test_build.go b/ui/build/test_build.go
new file mode 100644
index 00000000..d5e244c4
--- /dev/null
+++ b/ui/build/test_build.go
@@ -0,0 +1,78 @@
+// Copyright 2017 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 build
+
+import (
+ "bufio"
+ "path/filepath"
+ "strings"
+)
+
+// Checks for files in the out directory that have a rule that depends on them but no rule to
+// create them. This catches a common set of build failures where a rule to generate a file is
+// deleted (either by deleting a module in an Android.mk file, or by modifying the build system
+// incorrectly). These failures are often not caught by a local incremental build because the
+// previously built files are still present in the output directory.
+func testForDanglingRules(ctx Context, config Config) {
+ ctx.BeginTrace("test for dangling rules")
+ defer ctx.EndTrace()
+
+ // Get a list of leaf nodes in the dependency graph from ninja
+ executable := config.PrebuiltBuildTool("ninja")
+
+ args := []string{}
+ args = append(args, config.NinjaArgs()...)
+ args = append(args, "-f", config.CombinedNinjaFile())
+ args = append(args, "-t", "targets", "rule")
+
+ cmd := Command(ctx, config, "ninja", executable, args...)
+ stdout, err := cmd.StdoutPipe()
+ if err != nil {
+ ctx.Fatal(err)
+ }
+
+ cmd.StartOrFatal()
+
+ outDir := config.OutDir()
+ bootstrapDir := filepath.Join(outDir, "soong", ".bootstrap")
+ miniBootstrapDir := filepath.Join(outDir, "soong", ".minibootstrap")
+
+ var danglingRules []string
+
+ scanner := bufio.NewScanner(stdout)
+ for scanner.Scan() {
+ line := scanner.Text()
+ if !strings.HasPrefix(line, outDir) {
+ // Leaf node is not in the out directory.
+ continue
+ }
+ if strings.HasPrefix(line, bootstrapDir) || strings.HasPrefix(line, miniBootstrapDir) {
+ // Leaf node is in one of Soong's bootstrap directories, which do not have
+ // full build rules in the primary build.ninja file.
+ continue
+ }
+ danglingRules = append(danglingRules, line)
+ }
+
+ cmd.WaitOrFatal()
+
+ if len(danglingRules) > 0 {
+ ctx.Println("Dependencies in out found with no rule to create them:")
+ for _, dep := range danglingRules {
+ ctx.Println(dep)
+ }
+ ctx.Fatal("")
+ }
+}