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 15package build 16 17import ( 18 "io/ioutil" 19 "os" 20 "path/filepath" 21 "strconv" 22 "strings" 23 24 soong_metrics_proto "android/soong/ui/metrics/metrics_proto" 25 26 "github.com/golang/protobuf/proto" 27 "github.com/google/blueprint/microfactory" 28 29 "android/soong/ui/metrics" 30 "android/soong/ui/status" 31) 32 33func runSoong(ctx Context, config Config) { 34 ctx.BeginTrace(metrics.RunSoong, "soong") 35 defer ctx.EndTrace() 36 37 func() { 38 ctx.BeginTrace(metrics.RunSoong, "blueprint bootstrap") 39 defer ctx.EndTrace() 40 41 cmd := Command(ctx, config, "blueprint bootstrap", "build/blueprint/bootstrap.bash", "-t", "-n") 42 cmd.Environment.Set("BLUEPRINTDIR", "./build/blueprint") 43 cmd.Environment.Set("BOOTSTRAP", "./build/blueprint/bootstrap.bash") 44 cmd.Environment.Set("BUILDDIR", config.SoongOutDir()) 45 cmd.Environment.Set("GOROOT", "./"+filepath.Join("prebuilts/go", config.HostPrebuiltTag())) 46 cmd.Environment.Set("BLUEPRINT_LIST_FILE", filepath.Join(config.FileListDir(), "Android.bp.list")) 47 cmd.Environment.Set("NINJA_BUILDDIR", config.OutDir()) 48 cmd.Environment.Set("SRCDIR", ".") 49 cmd.Environment.Set("TOPNAME", "Android.bp") 50 cmd.Sandbox = soongSandbox 51 52 cmd.RunAndPrintOrFatal() 53 }() 54 55 func() { 56 ctx.BeginTrace(metrics.RunSoong, "environment check") 57 defer ctx.EndTrace() 58 59 envFile := filepath.Join(config.SoongOutDir(), ".soong.environment") 60 envTool := filepath.Join(config.SoongOutDir(), ".bootstrap/bin/soong_env") 61 if _, err := os.Stat(envFile); err == nil { 62 if _, err := os.Stat(envTool); err == nil { 63 cmd := Command(ctx, config, "soong_env", envTool, envFile) 64 cmd.Sandbox = soongSandbox 65 66 var buf strings.Builder 67 cmd.Stdout = &buf 68 cmd.Stderr = &buf 69 if err := cmd.Run(); err != nil { 70 ctx.Verboseln("soong_env failed, forcing manifest regeneration") 71 os.Remove(envFile) 72 } 73 74 if buf.Len() > 0 { 75 ctx.Verboseln(buf.String()) 76 } 77 } else { 78 ctx.Verboseln("Missing soong_env tool, forcing manifest regeneration") 79 os.Remove(envFile) 80 } 81 } else if !os.IsNotExist(err) { 82 ctx.Fatalf("Failed to stat %f: %v", envFile, err) 83 } 84 }() 85 86 var cfg microfactory.Config 87 cfg.Map("github.com/google/blueprint", "build/blueprint") 88 89 cfg.TrimPath = absPath(ctx, ".") 90 91 func() { 92 ctx.BeginTrace(metrics.RunSoong, "minibp") 93 defer ctx.EndTrace() 94 95 minibp := filepath.Join(config.SoongOutDir(), ".minibootstrap/minibp") 96 if _, err := microfactory.Build(&cfg, minibp, "github.com/google/blueprint/bootstrap/minibp"); err != nil { 97 ctx.Fatalln("Failed to build minibp:", err) 98 } 99 }() 100 101 func() { 102 ctx.BeginTrace(metrics.RunSoong, "bpglob") 103 defer ctx.EndTrace() 104 105 bpglob := filepath.Join(config.SoongOutDir(), ".minibootstrap/bpglob") 106 if _, err := microfactory.Build(&cfg, bpglob, "github.com/google/blueprint/bootstrap/bpglob"); err != nil { 107 ctx.Fatalln("Failed to build bpglob:", err) 108 } 109 }() 110 111 ninja := func(name, file string) { 112 ctx.BeginTrace(metrics.RunSoong, name) 113 defer ctx.EndTrace() 114 115 fifo := filepath.Join(config.OutDir(), ".ninja_fifo") 116 nr := status.NewNinjaReader(ctx, ctx.Status.StartTool(), fifo) 117 defer nr.Close() 118 119 cmd := Command(ctx, config, "soong "+name, 120 config.PrebuiltBuildTool("ninja"), 121 "-d", "keepdepfile", 122 "-d", "stats", 123 "-o", "usesphonyoutputs=yes", 124 "-o", "preremoveoutputs=yes", 125 "-w", "dupbuild=err", 126 "-w", "outputdir=err", 127 "-w", "missingoutfile=err", 128 "-j", strconv.Itoa(config.Parallel()), 129 "--frontend_file", fifo, 130 "-f", filepath.Join(config.SoongOutDir(), file)) 131 cmd.Environment.Set("SOONG_SANDBOX_SOONG_BUILD", "true") 132 cmd.Sandbox = soongSandbox 133 cmd.RunAndStreamOrFatal() 134 } 135 136 ninja("minibootstrap", ".minibootstrap/build.ninja") 137 ninja("bootstrap", ".bootstrap/build.ninja") 138 139 soongBuildMetrics := loadSoongBuildMetrics(ctx, config) 140 logSoongBuildMetrics(ctx, soongBuildMetrics) 141 142 distGzipFile(ctx, config, config.SoongNinjaFile(), "soong") 143 144 if !config.SkipMake() { 145 distGzipFile(ctx, config, config.SoongAndroidMk(), "soong") 146 distGzipFile(ctx, config, config.SoongMakeVarsMk(), "soong") 147 } 148 149 if ctx.Metrics != nil { 150 ctx.Metrics.SetSoongBuildMetrics(soongBuildMetrics) 151 } 152} 153 154func loadSoongBuildMetrics(ctx Context, config Config) *soong_metrics_proto.SoongBuildMetrics { 155 soongBuildMetricsFile := filepath.Join(config.OutDir(), "soong", "soong_build_metrics.pb") 156 buf, err := ioutil.ReadFile(soongBuildMetricsFile) 157 if err != nil { 158 ctx.Fatalf("Failed to load %s: %s", soongBuildMetricsFile, err) 159 } 160 soongBuildMetrics := &soong_metrics_proto.SoongBuildMetrics{} 161 err = proto.Unmarshal(buf, soongBuildMetrics) 162 if err != nil { 163 ctx.Fatalf("Failed to unmarshal %s: %s", soongBuildMetricsFile, err) 164 } 165 return soongBuildMetrics 166} 167 168func logSoongBuildMetrics(ctx Context, metrics *soong_metrics_proto.SoongBuildMetrics) { 169 ctx.Verbosef("soong_build metrics:") 170 ctx.Verbosef(" modules: %v", metrics.GetModules()) 171 ctx.Verbosef(" variants: %v", metrics.GetVariants()) 172 ctx.Verbosef(" max heap size: %v MB", metrics.GetMaxHeapSize()/1e6) 173 ctx.Verbosef(" total allocation count: %v", metrics.GetTotalAllocCount()) 174 ctx.Verbosef(" total allocation size: %v MB", metrics.GetTotalAllocSize()/1e6) 175 176} 177