blob: 884e95741ce333e0788af460ac1005b090bd8271 [file] [log] [blame]
Dan Willemsen1e704462016-08-21 15:17:17 -07001// 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 (
Colin Crossb72c9092020-02-10 11:23:49 -080018 "io/ioutil"
Dan Willemsen99a75cd2017-08-04 16:04:04 -070019 "os"
Dan Willemsen1e704462016-08-21 15:17:17 -070020 "path/filepath"
Dan Willemsen99a75cd2017-08-04 16:04:04 -070021 "strconv"
Dan Willemsen99a75cd2017-08-04 16:04:04 -070022
Lukacs T. Berki3243aa52021-02-25 14:44:14 +010023 "android/soong/shared"
Lukacs T. Berki7690c092021-02-26 14:27:36 +010024
Colin Crossb72c9092020-02-10 11:23:49 -080025 soong_metrics_proto "android/soong/ui/metrics/metrics_proto"
26
27 "github.com/golang/protobuf/proto"
Dan Willemsen99a75cd2017-08-04 16:04:04 -070028 "github.com/google/blueprint/microfactory"
Dan Willemsenb82471a2018-05-17 16:37:09 -070029
Nan Zhang17f27672018-12-12 16:01:49 -080030 "android/soong/ui/metrics"
Dan Willemsenb82471a2018-05-17 16:37:09 -070031 "android/soong/ui/status"
Dan Willemsen1e704462016-08-21 15:17:17 -070032)
33
Lukacs T. Berki7690c092021-02-26 14:27:36 +010034func writeEnvironmentFile(ctx Context, envFile string, envDeps map[string]string) error {
35 data, err := shared.EnvFileContents(envDeps)
36 if err != nil {
37 return err
38 }
39
40 return ioutil.WriteFile(envFile, data, 0644)
41}
42
Rupert Shuttleworthb7d97102020-11-25 10:19:29 +000043// This uses Android.bp files and various tools to generate <builddir>/build.ninja.
44//
45// However, the execution of <builddir>/build.ninja happens later in build/soong/ui/build/build.go#Build()
46//
47// We want to rely on as few prebuilts as possible, so there is some bootstrapping here.
48//
49// "Microfactory" is a tool for compiling Go code. We use it to build two other tools:
50// - minibp, used to generate build.ninja files. This is really build/blueprint/bootstrap/command.go#Main()
51// - bpglob, used during incremental builds to identify files in a glob that have changed
52//
53// In reality, several build.ninja files are generated and/or used during the bootstrapping and build process.
54// See build/blueprint/bootstrap/doc.go for more information.
55//
Dan Willemsen1e704462016-08-21 15:17:17 -070056func runSoong(ctx Context, config Config) {
Nan Zhang17f27672018-12-12 16:01:49 -080057 ctx.BeginTrace(metrics.RunSoong, "soong")
Dan Willemsend9f6fa22016-08-21 15:17:17 -070058 defer ctx.EndTrace()
59
Lukacs T. Berki7690c092021-02-26 14:27:36 +010060 // We have two environment files: .available is the one with every variable,
61 // .used with the ones that were actually used. The latter is used to
62 // determine whether Soong needs to be re-run since why re-run it if only
63 // unused variables were changed?
64 envFile := filepath.Join(config.SoongOutDir(), "soong.environment.available")
65
Rupert Shuttleworthb7d97102020-11-25 10:19:29 +000066 // Use an anonymous inline function for tracing purposes (this pattern is used several times below).
Dan Willemsen99a75cd2017-08-04 16:04:04 -070067 func() {
Nan Zhang17f27672018-12-12 16:01:49 -080068 ctx.BeginTrace(metrics.RunSoong, "blueprint bootstrap")
Dan Willemsen99a75cd2017-08-04 16:04:04 -070069 defer ctx.EndTrace()
70
Rupert Shuttleworthb7d97102020-11-25 10:19:29 +000071 // Use validations to depend on tests.
Colin Cross00a8a3f2020-10-29 14:08:31 -070072 args := []string{"-n"}
Rupert Shuttleworthb7d97102020-11-25 10:19:29 +000073
Colin Cross00a8a3f2020-10-29 14:08:31 -070074 if !config.skipSoongTests {
Rupert Shuttleworthb7d97102020-11-25 10:19:29 +000075 // Run tests.
Colin Cross00a8a3f2020-10-29 14:08:31 -070076 args = append(args, "-t")
77 }
78
79 cmd := Command(ctx, config, "blueprint bootstrap", "build/blueprint/bootstrap.bash", args...)
Lukacs T. Berki7690c092021-02-26 14:27:36 +010080
Dan Willemsen99a75cd2017-08-04 16:04:04 -070081 cmd.Environment.Set("BLUEPRINTDIR", "./build/blueprint")
82 cmd.Environment.Set("BOOTSTRAP", "./build/blueprint/bootstrap.bash")
83 cmd.Environment.Set("BUILDDIR", config.SoongOutDir())
Dan Willemsene7945d72018-01-23 22:15:15 -080084 cmd.Environment.Set("GOROOT", "./"+filepath.Join("prebuilts/go", config.HostPrebuiltTag()))
Jeff Gastond3e141d2017-08-08 17:46:01 -070085 cmd.Environment.Set("BLUEPRINT_LIST_FILE", filepath.Join(config.FileListDir(), "Android.bp.list"))
Dan Willemsen99a75cd2017-08-04 16:04:04 -070086 cmd.Environment.Set("NINJA_BUILDDIR", config.OutDir())
87 cmd.Environment.Set("SRCDIR", ".")
88 cmd.Environment.Set("TOPNAME", "Android.bp")
89 cmd.Sandbox = soongSandbox
Dan Willemsenb82471a2018-05-17 16:37:09 -070090
91 cmd.RunAndPrintOrFatal()
Dan Willemsen99a75cd2017-08-04 16:04:04 -070092 }()
93
Lukacs T. Berki7690c092021-02-26 14:27:36 +010094 soongBuildEnv := config.Environment().Copy()
95 soongBuildEnv.Set("TOP", os.Getenv("TOP"))
96 // These two dependencies are read from bootstrap.go, but also need to be here
97 // so that soong_build can declare a dependency on them
98 soongBuildEnv.Set("SOONG_DELVE", os.Getenv("SOONG_DELVE"))
99 soongBuildEnv.Set("SOONG_DELVE_PATH", os.Getenv("SOONG_DELVE_PATH"))
100 soongBuildEnv.Set("SOONG_OUTDIR", config.SoongOutDir())
101 // For Bazel mixed builds.
102 soongBuildEnv.Set("BAZEL_PATH", "./tools/bazel")
103 soongBuildEnv.Set("BAZEL_HOME", filepath.Join(config.BazelOutDir(), "bazelhome"))
104 soongBuildEnv.Set("BAZEL_OUTPUT_BASE", filepath.Join(config.BazelOutDir(), "output"))
105 soongBuildEnv.Set("BAZEL_WORKSPACE", absPath(ctx, "."))
106 soongBuildEnv.Set("BAZEL_METRICS_DIR", config.BazelMetricsDir())
107
Paul Duffin5e85c662021-03-05 12:26:14 +0000108 err := writeEnvironmentFile(ctx, envFile, soongBuildEnv.AsMap())
109 if err != nil {
110 ctx.Fatalf("failed to write environment file %s: %s", envFile, err)
111 }
Lukacs T. Berki7690c092021-02-26 14:27:36 +0100112
Dan Willemsen99a75cd2017-08-04 16:04:04 -0700113 func() {
Nan Zhang17f27672018-12-12 16:01:49 -0800114 ctx.BeginTrace(metrics.RunSoong, "environment check")
Dan Willemsen99a75cd2017-08-04 16:04:04 -0700115 defer ctx.EndTrace()
116
Lukacs T. Berki7690c092021-02-26 14:27:36 +0100117 envFile := filepath.Join(config.SoongOutDir(), "soong.environment.used")
Lukacs T. Berki3243aa52021-02-25 14:44:14 +0100118 getenv := func(k string) string {
Lukacs T. Berkib4ced9d2021-03-10 15:43:06 +0100119 v, _ := soongBuildEnv.Get(k)
Lukacs T. Berki3243aa52021-02-25 14:44:14 +0100120 return v
121 }
122 if stale, _ := shared.StaleEnvFile(envFile, getenv); stale {
123 os.Remove(envFile)
Dan Willemsen99a75cd2017-08-04 16:04:04 -0700124 }
125 }()
126
Dan Willemsen5af1cbe2018-07-05 21:46:51 -0700127 var cfg microfactory.Config
128 cfg.Map("github.com/google/blueprint", "build/blueprint")
129
130 cfg.TrimPath = absPath(ctx, ".")
131
Dan Willemsen99a75cd2017-08-04 16:04:04 -0700132 func() {
Nan Zhang17f27672018-12-12 16:01:49 -0800133 ctx.BeginTrace(metrics.RunSoong, "minibp")
Dan Willemsen99a75cd2017-08-04 16:04:04 -0700134 defer ctx.EndTrace()
135
Dan Willemsen99a75cd2017-08-04 16:04:04 -0700136 minibp := filepath.Join(config.SoongOutDir(), ".minibootstrap/minibp")
137 if _, err := microfactory.Build(&cfg, minibp, "github.com/google/blueprint/bootstrap/minibp"); err != nil {
138 ctx.Fatalln("Failed to build minibp:", err)
139 }
140 }()
141
Dan Willemsen5af1cbe2018-07-05 21:46:51 -0700142 func() {
Nan Zhang17f27672018-12-12 16:01:49 -0800143 ctx.BeginTrace(metrics.RunSoong, "bpglob")
Dan Willemsen5af1cbe2018-07-05 21:46:51 -0700144 defer ctx.EndTrace()
145
146 bpglob := filepath.Join(config.SoongOutDir(), ".minibootstrap/bpglob")
147 if _, err := microfactory.Build(&cfg, bpglob, "github.com/google/blueprint/bootstrap/bpglob"); err != nil {
148 ctx.Fatalln("Failed to build bpglob:", err)
149 }
150 }()
151
Dan Willemsen99a75cd2017-08-04 16:04:04 -0700152 ninja := func(name, file string) {
Nan Zhang17f27672018-12-12 16:01:49 -0800153 ctx.BeginTrace(metrics.RunSoong, name)
Dan Willemsen99a75cd2017-08-04 16:04:04 -0700154 defer ctx.EndTrace()
155
Dan Willemsenb82471a2018-05-17 16:37:09 -0700156 fifo := filepath.Join(config.OutDir(), ".ninja_fifo")
Colin Crossb98d3bc2019-03-21 16:02:58 -0700157 nr := status.NewNinjaReader(ctx, ctx.Status.StartTool(), fifo)
158 defer nr.Close()
Dan Willemsenb82471a2018-05-17 16:37:09 -0700159
Dan Willemsen99a75cd2017-08-04 16:04:04 -0700160 cmd := Command(ctx, config, "soong "+name,
161 config.PrebuiltBuildTool("ninja"),
162 "-d", "keepdepfile",
Dan Willemsen08218222020-05-18 14:02:02 -0700163 "-d", "stats",
Dan Willemsen6587bed2020-04-18 20:25:59 -0700164 "-o", "usesphonyoutputs=yes",
165 "-o", "preremoveoutputs=yes",
Dan Willemsen99a75cd2017-08-04 16:04:04 -0700166 "-w", "dupbuild=err",
Dan Willemsen6587bed2020-04-18 20:25:59 -0700167 "-w", "outputdir=err",
168 "-w", "missingoutfile=err",
Dan Willemsen99a75cd2017-08-04 16:04:04 -0700169 "-j", strconv.Itoa(config.Parallel()),
Dan Willemsen02736672018-07-17 17:54:31 -0700170 "--frontend_file", fifo,
Dan Willemsen99a75cd2017-08-04 16:04:04 -0700171 "-f", filepath.Join(config.SoongOutDir(), file))
Jingwen Chen7c6089a2020-11-02 02:56:20 -0500172
Lukacs T. Berkib14ad7b2021-03-09 10:43:57 +0100173 var ninjaEnv Environment
Lukacs T. Berki73ab9282021-03-10 10:48:39 +0100174
175 // This is currently how the command line to invoke soong_build finds the
176 // root of the source tree and the output root
Lukacs T. Berkib14ad7b2021-03-09 10:43:57 +0100177 ninjaEnv.Set("TOP", os.Getenv("TOP"))
178 ninjaEnv.Set("SOONG_OUTDIR", config.SoongOutDir())
Lukacs T. Berki73ab9282021-03-10 10:48:39 +0100179
Lukacs T. Berki73ab9282021-03-10 10:48:39 +0100180 // For debugging
Lukacs T. Berki7d613bf2021-03-02 10:09:41 +0100181 if os.Getenv("SOONG_DELVE") != "" {
Lukacs T. Berkib4ced9d2021-03-10 15:43:06 +0100182 ninjaEnv.Set("SOONG_DELVE", os.Getenv("SOONG_DELVE"))
Lukacs T. Berkib14ad7b2021-03-09 10:43:57 +0100183 ninjaEnv.Set("SOONG_DELVE_PATH", shared.ResolveDelveBinary())
Lukacs T. Berki7d613bf2021-03-02 10:09:41 +0100184 }
185
Lukacs T. Berkib14ad7b2021-03-09 10:43:57 +0100186 cmd.Environment = &ninjaEnv
Dan Willemsen99a75cd2017-08-04 16:04:04 -0700187 cmd.Sandbox = soongSandbox
Colin Cross7b97ecd2019-06-19 13:17:59 -0700188 cmd.RunAndStreamOrFatal()
Dan Willemsen1e704462016-08-21 15:17:17 -0700189 }
Dan Willemsen99a75cd2017-08-04 16:04:04 -0700190
Rupert Shuttleworthb7d97102020-11-25 10:19:29 +0000191 // This build generates .bootstrap/build.ninja, which is used in the next step.
Dan Willemsen99a75cd2017-08-04 16:04:04 -0700192 ninja("minibootstrap", ".minibootstrap/build.ninja")
Rupert Shuttleworthb7d97102020-11-25 10:19:29 +0000193
194 // This build generates <builddir>/build.ninja, which is used later by build/soong/ui/build/build.go#Build().
Dan Willemsen99a75cd2017-08-04 16:04:04 -0700195 ninja("bootstrap", ".bootstrap/build.ninja")
Colin Crossb72c9092020-02-10 11:23:49 -0800196
Jingwen Cheneb76c432021-01-28 08:22:12 -0500197 var soongBuildMetrics *soong_metrics_proto.SoongBuildMetrics
198 if shouldCollectBuildSoongMetrics(config) {
199 soongBuildMetrics := loadSoongBuildMetrics(ctx, config)
200 logSoongBuildMetrics(ctx, soongBuildMetrics)
201 }
Colin Crossb72c9092020-02-10 11:23:49 -0800202
Colin Cross8ba7d472020-06-25 11:27:52 -0700203 distGzipFile(ctx, config, config.SoongNinjaFile(), "soong")
204
Anton Hansson5e5c48b2020-11-27 12:35:20 +0000205 if !config.SkipKati() {
Colin Cross8ba7d472020-06-25 11:27:52 -0700206 distGzipFile(ctx, config, config.SoongAndroidMk(), "soong")
207 distGzipFile(ctx, config, config.SoongMakeVarsMk(), "soong")
208 }
209
Jingwen Cheneb76c432021-01-28 08:22:12 -0500210 if shouldCollectBuildSoongMetrics(config) && ctx.Metrics != nil {
Colin Crossb72c9092020-02-10 11:23:49 -0800211 ctx.Metrics.SetSoongBuildMetrics(soongBuildMetrics)
212 }
213}
214
Jingwen Cheneb76c432021-01-28 08:22:12 -0500215func shouldCollectBuildSoongMetrics(config Config) bool {
216 // Do not collect metrics protobuf if the soong_build binary ran as the bp2build converter.
217 return config.Environment().IsFalse("GENERATE_BAZEL_FILES")
218}
219
Colin Crossb72c9092020-02-10 11:23:49 -0800220func loadSoongBuildMetrics(ctx Context, config Config) *soong_metrics_proto.SoongBuildMetrics {
221 soongBuildMetricsFile := filepath.Join(config.OutDir(), "soong", "soong_build_metrics.pb")
222 buf, err := ioutil.ReadFile(soongBuildMetricsFile)
223 if err != nil {
224 ctx.Fatalf("Failed to load %s: %s", soongBuildMetricsFile, err)
225 }
226 soongBuildMetrics := &soong_metrics_proto.SoongBuildMetrics{}
227 err = proto.Unmarshal(buf, soongBuildMetrics)
228 if err != nil {
229 ctx.Fatalf("Failed to unmarshal %s: %s", soongBuildMetricsFile, err)
230 }
231 return soongBuildMetrics
232}
233
234func logSoongBuildMetrics(ctx Context, metrics *soong_metrics_proto.SoongBuildMetrics) {
235 ctx.Verbosef("soong_build metrics:")
236 ctx.Verbosef(" modules: %v", metrics.GetModules())
237 ctx.Verbosef(" variants: %v", metrics.GetVariants())
238 ctx.Verbosef(" max heap size: %v MB", metrics.GetMaxHeapSize()/1e6)
239 ctx.Verbosef(" total allocation count: %v", metrics.GetTotalAllocCount())
240 ctx.Verbosef(" total allocation size: %v MB", metrics.GetTotalAllocSize()/1e6)
241
Dan Willemsen1e704462016-08-21 15:17:17 -0700242}