1 // 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 15 package build 16 17 import ( 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. 29 func 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 } 86