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 "io/ioutil" 19 "os" 20 "path/filepath" 21 "text/template" 22 ) 23 24 // Ensures the out directory exists, and has the proper files to prevent kati 25 // from recursing into it. 26 func SetupOutDir(ctx Context, config Config) { 27 ensureEmptyFileExists(ctx, filepath.Join(config.OutDir(), "Android.mk")) 28 ensureEmptyFileExists(ctx, filepath.Join(config.OutDir(), "CleanSpec.mk")) 29 ensureEmptyFileExists(ctx, filepath.Join(config.SoongOutDir(), ".soong.in_make")) 30 // The ninja_build file is used by our buildbots to understand that the output 31 // can be parsed as ninja output. 32 ensureEmptyFileExists(ctx, filepath.Join(config.OutDir(), "ninja_build")) 33 } 34 35 var combinedBuildNinjaTemplate = template.Must(template.New("combined").Parse(` 36 builddir = {{.OutDir}} 37 include {{.KatiNinjaFile}} 38 include {{.SoongNinjaFile}} 39 build {{.CombinedNinjaFile}}: phony {{.SoongNinjaFile}} 40 `)) 41 42 func createCombinedBuildNinjaFile(ctx Context, config Config) { 43 file, err := os.Create(config.CombinedNinjaFile()) 44 if err != nil { 45 ctx.Fatalln("Failed to create combined ninja file:", err) 46 } 47 defer file.Close() 48 49 if err := combinedBuildNinjaTemplate.Execute(file, config); err != nil { 50 ctx.Fatalln("Failed to write combined ninja file:", err) 51 } 52 } 53 54 const ( 55 BuildNone = iota 56 BuildProductConfig = 1 << iota 57 BuildSoong = 1 << iota 58 BuildKati = 1 << iota 59 BuildNinja = 1 << iota 60 BuildAll = BuildProductConfig | BuildSoong | BuildKati | BuildNinja 61 ) 62 63 func checkCaseSensitivity(ctx Context, config Config) { 64 outDir := config.OutDir() 65 lowerCase := filepath.Join(outDir, "casecheck.txt") 66 upperCase := filepath.Join(outDir, "CaseCheck.txt") 67 lowerData := "a" 68 upperData := "B" 69 70 err := ioutil.WriteFile(lowerCase, []byte(lowerData), 0777) 71 if err != nil { 72 ctx.Fatalln("Failed to check case sensitivity:", err) 73 } 74 75 err = ioutil.WriteFile(upperCase, []byte(upperData), 0777) 76 if err != nil { 77 ctx.Fatalln("Failed to check case sensitivity:", err) 78 } 79 80 res, err := ioutil.ReadFile(lowerCase) 81 if err != nil { 82 ctx.Fatalln("Failed to check case sensitivity:", err) 83 } 84 85 if string(res) != lowerData { 86 ctx.Println("************************************************************") 87 ctx.Println("You are building on a case-insensitive filesystem.") 88 ctx.Println("Please move your source tree to a case-sensitive filesystem.") 89 ctx.Println("************************************************************") 90 ctx.Fatalln("Case-insensitive filesystems not supported") 91 } 92 } 93 94 func help(ctx Context, config Config, what int) { 95 cmd := Command(ctx, config, "make", 96 "make", "-f", "build/core/help.mk") 97 cmd.Sandbox = makeSandbox 98 cmd.Stdout = ctx.Stdout() 99 cmd.Stderr = ctx.Stderr() 100 cmd.RunOrFatal() 101 } 102 103 // Build the tree. The 'what' argument can be used to chose which components of 104 // the build to run. 105 func Build(ctx Context, config Config, what int) { 106 ctx.Verboseln("Starting build with args:", config.Arguments()) 107 ctx.Verboseln("Environment:", config.Environment().Environ()) 108 109 if inList("help", config.Arguments()) { 110 help(ctx, config, what) 111 return 112 } else if inList("clean", config.Arguments()) || inList("clobber", config.Arguments()) { 113 clean(ctx, config, what) 114 return 115 } 116 117 // Start getting java version as early as possible 118 getJavaVersions(ctx, config) 119 120 // Make sure that no other Soong process is running with the same output directory 121 buildLock := BecomeSingletonOrFail(ctx, config) 122 defer buildLock.Unlock() 123 124 SetupOutDir(ctx, config) 125 126 checkCaseSensitivity(ctx, config) 127 128 ensureEmptyDirectoriesExist(ctx, config.TempDir()) 129 130 if what&BuildProductConfig != 0 { 131 // Run make for product config 132 runMakeProductConfig(ctx, config) 133 } 134 135 if inList("installclean", config.Arguments()) { 136 installClean(ctx, config, what) 137 ctx.Println("Deleted images and staging directories.") 138 return 139 } else if inList("dataclean", config.Arguments()) { 140 dataClean(ctx, config, what) 141 ctx.Println("Deleted data files.") 142 return 143 } 144 145 if what&BuildSoong != 0 { 146 // Run Soong 147 runSoongBootstrap(ctx, config) 148 runSoong(ctx, config) 149 } 150 151 // Check the java versions we read earlier 152 checkJavaVersion(ctx, config) 153 154 if what&BuildKati != 0 { 155 // Run ckati 156 runKati(ctx, config) 157 } 158 159 if what&BuildNinja != 0 { 160 installCleanIfNecessary(ctx, config) 161 162 // Write combined ninja file 163 createCombinedBuildNinjaFile(ctx, config) 164 165 // Run ninja 166 runNinja(ctx, config) 167 } 168 } 169