blob: 940f0c89fd05ab1a4504114c6098f4d1b8a9f187 [file] [log] [blame]
Colin Cross37193492017-11-16 17:55:00 -08001// Copyright 2017 Google Inc. All rights reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package build
16
17import (
18 "bufio"
19 "path/filepath"
20 "runtime"
21 "strings"
22)
23
24// Checks for files in the out directory that have a rule that depends on them but no rule to
25// create them. This catches a common set of build failures where a rule to generate a file is
26// deleted (either by deleting a module in an Android.mk file, or by modifying the build system
27// incorrectly). These failures are often not caught by a local incremental build because the
28// previously built files are still present in the output directory.
29func testForDanglingRules(ctx Context, config Config) {
30 // Many modules are disabled on mac. Checking for dangling rules would cause lots of build
31 // breakages, and presubmit wouldn't catch them, so just disable the check.
32 if runtime.GOOS != "linux" {
33 return
34 }
35
36 ctx.BeginTrace("test for dangling rules")
37 defer ctx.EndTrace()
38
39 // Get a list of leaf nodes in the dependency graph from ninja
40 executable := config.PrebuiltBuildTool("ninja")
41
42 args := []string{}
43 args = append(args, config.NinjaArgs()...)
44 args = append(args, "-f", config.CombinedNinjaFile())
45 args = append(args, "-t", "targets", "rule")
46
47 cmd := Command(ctx, config, "ninja", executable, args...)
48 stdout, err := cmd.StdoutPipe()
49 if err != nil {
50 ctx.Fatal(err)
51 }
52
53 cmd.StartOrFatal()
54
55 outDir := config.OutDir()
56 bootstrapDir := filepath.Join(outDir, "soong", ".bootstrap")
57 miniBootstrapDir := filepath.Join(outDir, "soong", ".minibootstrap")
58
59 var danglingRules []string
60
61 scanner := bufio.NewScanner(stdout)
62 for scanner.Scan() {
63 line := scanner.Text()
64 if !strings.HasPrefix(line, outDir) {
65 // Leaf node is not in the out directory.
66 continue
67 }
68 if strings.HasPrefix(line, bootstrapDir) || strings.HasPrefix(line, miniBootstrapDir) {
69 // Leaf node is in one of Soong's bootstrap directories, which do not have
70 // full build rules in the primary build.ninja file.
71 continue
72 }
73 danglingRules = append(danglingRules, line)
74 }
75
76 cmd.WaitOrFatal()
77
78 if len(danglingRules) > 0 {
79 ctx.Println("Dependencies in out found with no rule to create them:")
80 for _, dep := range danglingRules {
81 ctx.Println(dep)
82 }
83 ctx.Fatal("")
84 }
85}