Merge "Soong support for namespaces"
diff --git a/androidmk/cmd/androidmk/android.go b/androidmk/cmd/androidmk/android.go
index df01cf4..73ea4ac 100644
--- a/androidmk/cmd/androidmk/android.go
+++ b/androidmk/cmd/androidmk/android.go
@@ -24,7 +24,8 @@
)
const (
- clear_vars = "__android_mk_clear_vars"
+ clear_vars = "__android_mk_clear_vars"
+ include_ignored = "__android_mk_include_ignored"
)
type bpVariable struct {
@@ -693,6 +694,10 @@
return "**/*.java"
}
+func includeIgnored(args []string) string {
+ return include_ignored
+}
+
var moduleTypes = map[string]string{
"BUILD_SHARED_LIBRARY": "cc_library_shared",
"BUILD_STATIC_LIBRARY": "cc_library_static",
@@ -729,6 +734,10 @@
globalScope.SetFunc("all-java-files-under", allJavaFilesUnder)
globalScope.SetFunc("all-proto-files-under", allProtoFilesUnder)
globalScope.SetFunc("all-subdir-java-files", allSubdirJavaFiles)
+ globalScope.SetFunc("all-makefiles-under", includeIgnored)
+ globalScope.SetFunc("first-makefiles-under", includeIgnored)
+ globalScope.SetFunc("all-named-subdir-makefiles", includeIgnored)
+ globalScope.SetFunc("all-subdir-makefiles", includeIgnored)
for k, v := range moduleTypes {
globalScope.Set(k, v)
diff --git a/androidmk/cmd/androidmk/androidmk.go b/androidmk/cmd/androidmk/androidmk.go
index 660d9a0..385690c 100644
--- a/androidmk/cmd/androidmk/androidmk.go
+++ b/androidmk/cmd/androidmk/androidmk.go
@@ -177,6 +177,9 @@
makeModule(file, val)
case val == clear_vars:
resetModule(file)
+ case val == include_ignored:
+ // subdirs are already automatically included in Soong
+ continue
default:
file.errorf(x, "unsupported include")
continue
diff --git a/androidmk/cmd/androidmk/androidmk_test.go b/androidmk/cmd/androidmk/androidmk_test.go
index 0b86540..9986889 100644
--- a/androidmk/cmd/androidmk/androidmk_test.go
+++ b/androidmk/cmd/androidmk/androidmk_test.go
@@ -460,6 +460,13 @@
// endif
`,
},
+ {
+ desc: "ignore all-makefiles-under",
+ in: `
+include $(call all-makefiles-under,$(LOCAL_PATH))
+`,
+ expected: ``,
+ },
}
func reformatBlueprint(input string) string {
diff --git a/cmd/soong_ui/main.go b/cmd/soong_ui/main.go
index 0619b5c..2ca7ebf 100644
--- a/cmd/soong_ui/main.go
+++ b/cmd/soong_ui/main.go
@@ -114,7 +114,11 @@
} else if os.Args[1] == "--dumpvars-mode" {
dumpVars(buildCtx, config, os.Args[2:])
} else {
- build.Build(buildCtx, config, build.BuildAll)
+ toBuild := build.BuildAll
+ if config.Checkbuild() {
+ toBuild |= build.RunBuildTests
+ }
+ build.Build(buildCtx, config, toBuild)
}
}
diff --git a/ui/build/Android.bp b/ui/build/Android.bp
index d1b4943..5809894 100644
--- a/ui/build/Android.bp
+++ b/ui/build/Android.bp
@@ -36,6 +36,7 @@
"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 0df22b3..78eb6a3 100644
--- a/ui/build/build.go
+++ b/ui/build/build.go
@@ -68,6 +68,7 @@
BuildSoong = 1 << iota
BuildKati = 1 << iota
BuildNinja = 1 << iota
+ RunBuildTests = 1 << iota
BuildAll = BuildProductConfig | BuildSoong | BuildKati | BuildNinja
)
@@ -172,14 +173,18 @@
}
}
+ // 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 6e5559d..df97d80 100644
--- a/ui/build/config.go
+++ b/ui/build/config.go
@@ -34,11 +34,12 @@
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 @@
} else {
if arg == "dist" {
c.dist = true
+ } else if arg == "checkbuild" {
+ c.checkbuild = true
}
c.arguments = append(c.arguments, arg)
}
@@ -313,6 +316,12 @@
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 0000000..940f0c8
--- /dev/null
+++ b/ui/build/test_build.go
@@ -0,0 +1,85 @@
+// 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"
+ "runtime"
+ "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) {
+ // Many modules are disabled on mac. Checking for dangling rules would cause lots of build
+ // breakages, and presubmit wouldn't catch them, so just disable the check.
+ if runtime.GOOS != "linux" {
+ return
+ }
+
+ 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("")
+ }
+}