blob: 4a251197281ea483c939d6d6cc4f67c78ac25848 [file] [log] [blame]
Chris Parsonsf3c96ef2020-09-29 02:23:17 -04001// Copyright 2020 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 android
16
17import (
18 "bytes"
19 "errors"
20 "fmt"
Chris Parsonsa798d962020-10-12 23:44:08 -040021 "io/ioutil"
Chris Parsonsf3c96ef2020-09-29 02:23:17 -040022 "os"
23 "os/exec"
Chris Parsonsa798d962020-10-12 23:44:08 -040024 "path/filepath"
Chris Parsonsf3c96ef2020-09-29 02:23:17 -040025 "runtime"
26 "strings"
27 "sync"
Chris Parsonsa798d962020-10-12 23:44:08 -040028
Chris Parsonsdbcb1ff2020-12-10 17:19:18 -050029 "github.com/google/blueprint/bootstrap"
30
Patrice Arruda05ab2d02020-12-12 06:24:26 +000031 "android/soong/bazel"
32 "android/soong/shared"
Chris Parsonsf3c96ef2020-09-29 02:23:17 -040033)
34
Chris Parsonsb0f8ac42020-10-23 16:48:08 -040035type CqueryRequestType int
36
37const (
38 getAllFiles CqueryRequestType = iota
39)
40
Chris Parsonsf3c96ef2020-09-29 02:23:17 -040041// Map key to describe bazel cquery requests.
42type cqueryKey struct {
Chris Parsonsb0f8ac42020-10-23 16:48:08 -040043 label string
44 requestType CqueryRequestType
Chris Parsonsf3c96ef2020-09-29 02:23:17 -040045}
46
47type BazelContext interface {
48 // The below methods involve queuing cquery requests to be later invoked
49 // by bazel. If any of these methods return (_, false), then the request
50 // has been queued to be run later.
51
52 // Returns result files built by building the given bazel target label.
53 GetAllFiles(label string) ([]string, bool)
54
55 // TODO(cparsons): Other cquery-related methods should be added here.
56 // ** End cquery methods
57
58 // Issues commands to Bazel to receive results for all cquery requests
59 // queued in the BazelContext.
60 InvokeBazel() error
61
62 // Returns true if bazel is enabled for the given configuration.
63 BazelEnabled() bool
Chris Parsonsdbcb1ff2020-12-10 17:19:18 -050064
65 // Returns the bazel output base (the root directory for all bazel intermediate outputs).
66 OutputBase() string
67
68 // Returns build statements which should get registered to reflect Bazel's outputs.
69 BuildStatementsToRegister() []bazel.BuildStatement
Chris Parsonsf3c96ef2020-09-29 02:23:17 -040070}
71
72// A context object which tracks queued requests that need to be made to Bazel,
73// and their results after the requests have been made.
74type bazelContext struct {
75 homeDir string
76 bazelPath string
77 outputBase string
78 workspaceDir string
Chris Parsonsb0f8ac42020-10-23 16:48:08 -040079 buildDir string
Patrice Arruda05ab2d02020-12-12 06:24:26 +000080 metricsDir string
Chris Parsonsf3c96ef2020-09-29 02:23:17 -040081
82 requests map[cqueryKey]bool // cquery requests that have not yet been issued to Bazel
83 requestMutex sync.Mutex // requests can be written in parallel
84
85 results map[cqueryKey]string // Results of cquery requests after Bazel invocations
Chris Parsonsdbcb1ff2020-12-10 17:19:18 -050086
87 // Build statements which should get registered to reflect Bazel's outputs.
88 buildStatements []bazel.BuildStatement
Chris Parsonsf3c96ef2020-09-29 02:23:17 -040089}
90
91var _ BazelContext = &bazelContext{}
92
93// A bazel context to use when Bazel is disabled.
94type noopBazelContext struct{}
95
96var _ BazelContext = noopBazelContext{}
97
98// A bazel context to use for tests.
99type MockBazelContext struct {
100 AllFiles map[string][]string
101}
102
103func (m MockBazelContext) GetAllFiles(label string) ([]string, bool) {
104 result, ok := m.AllFiles[label]
105 return result, ok
106}
107
108func (m MockBazelContext) InvokeBazel() error {
109 panic("unimplemented")
110}
111
112func (m MockBazelContext) BazelEnabled() bool {
113 return true
114}
115
Chris Parsonsdbcb1ff2020-12-10 17:19:18 -0500116func (m MockBazelContext) OutputBase() string {
117 return "outputbase"
118}
119
120func (m MockBazelContext) BuildStatementsToRegister() []bazel.BuildStatement {
121 return []bazel.BuildStatement{}
122}
123
Chris Parsonsf3c96ef2020-09-29 02:23:17 -0400124var _ BazelContext = MockBazelContext{}
125
126func (bazelCtx *bazelContext) GetAllFiles(label string) ([]string, bool) {
Chris Parsonsb0f8ac42020-10-23 16:48:08 -0400127 result, ok := bazelCtx.cquery(label, getAllFiles)
Chris Parsonsf3c96ef2020-09-29 02:23:17 -0400128 if ok {
129 bazelOutput := strings.TrimSpace(result)
130 return strings.Split(bazelOutput, ", "), true
131 } else {
132 return nil, false
133 }
134}
135
136func (n noopBazelContext) GetAllFiles(label string) ([]string, bool) {
137 panic("unimplemented")
138}
139
140func (n noopBazelContext) InvokeBazel() error {
141 panic("unimplemented")
142}
143
Chris Parsonsdbcb1ff2020-12-10 17:19:18 -0500144func (m noopBazelContext) OutputBase() string {
145 return ""
146}
147
Chris Parsonsf3c96ef2020-09-29 02:23:17 -0400148func (n noopBazelContext) BazelEnabled() bool {
149 return false
150}
151
Chris Parsonsdbcb1ff2020-12-10 17:19:18 -0500152func (m noopBazelContext) BuildStatementsToRegister() []bazel.BuildStatement {
153 return []bazel.BuildStatement{}
154}
155
Chris Parsonsf3c96ef2020-09-29 02:23:17 -0400156func NewBazelContext(c *config) (BazelContext, error) {
Chris Parsons8b77a002020-10-27 18:59:25 -0400157 // TODO(cparsons): Assess USE_BAZEL=1 instead once "mixed Soong/Bazel builds"
158 // are production ready.
159 if c.Getenv("USE_BAZEL_ANALYSIS") != "1" {
Chris Parsonsf3c96ef2020-09-29 02:23:17 -0400160 return noopBazelContext{}, nil
161 }
162
Chris Parsonsb0f8ac42020-10-23 16:48:08 -0400163 bazelCtx := bazelContext{buildDir: c.buildDir, requests: make(map[cqueryKey]bool)}
Chris Parsonsf3c96ef2020-09-29 02:23:17 -0400164 missingEnvVars := []string{}
165 if len(c.Getenv("BAZEL_HOME")) > 1 {
166 bazelCtx.homeDir = c.Getenv("BAZEL_HOME")
167 } else {
168 missingEnvVars = append(missingEnvVars, "BAZEL_HOME")
169 }
170 if len(c.Getenv("BAZEL_PATH")) > 1 {
171 bazelCtx.bazelPath = c.Getenv("BAZEL_PATH")
172 } else {
173 missingEnvVars = append(missingEnvVars, "BAZEL_PATH")
174 }
175 if len(c.Getenv("BAZEL_OUTPUT_BASE")) > 1 {
176 bazelCtx.outputBase = c.Getenv("BAZEL_OUTPUT_BASE")
177 } else {
178 missingEnvVars = append(missingEnvVars, "BAZEL_OUTPUT_BASE")
179 }
180 if len(c.Getenv("BAZEL_WORKSPACE")) > 1 {
181 bazelCtx.workspaceDir = c.Getenv("BAZEL_WORKSPACE")
182 } else {
183 missingEnvVars = append(missingEnvVars, "BAZEL_WORKSPACE")
184 }
Patrice Arruda05ab2d02020-12-12 06:24:26 +0000185 if len(c.Getenv("BAZEL_METRICS_DIR")) > 1 {
186 bazelCtx.metricsDir = c.Getenv("BAZEL_METRICS_DIR")
187 } else {
188 missingEnvVars = append(missingEnvVars, "BAZEL_METRICS_DIR")
189 }
Chris Parsonsf3c96ef2020-09-29 02:23:17 -0400190 if len(missingEnvVars) > 0 {
191 return nil, errors.New(fmt.Sprintf("missing required env vars to use bazel: %s", missingEnvVars))
192 } else {
193 return &bazelCtx, nil
194 }
195}
196
Patrice Arruda05ab2d02020-12-12 06:24:26 +0000197func (context *bazelContext) BazelMetricsDir() string {
198 return context.metricsDir
199}
200
Chris Parsonsf3c96ef2020-09-29 02:23:17 -0400201func (context *bazelContext) BazelEnabled() bool {
202 return true
203}
204
205// Adds a cquery request to the Bazel request queue, to be later invoked, or
206// returns the result of the given request if the request was already made.
207// If the given request was already made (and the results are available), then
208// returns (result, true). If the request is queued but no results are available,
209// then returns ("", false).
Chris Parsonsb0f8ac42020-10-23 16:48:08 -0400210func (context *bazelContext) cquery(label string, requestType CqueryRequestType) (string, bool) {
211 key := cqueryKey{label, requestType}
Chris Parsonsf3c96ef2020-09-29 02:23:17 -0400212 if result, ok := context.results[key]; ok {
213 return result, true
214 } else {
215 context.requestMutex.Lock()
216 defer context.requestMutex.Unlock()
217 context.requests[key] = true
218 return "", false
219 }
220}
221
222func pwdPrefix() string {
223 // Darwin doesn't have /proc
224 if runtime.GOOS != "darwin" {
225 return "PWD=/proc/self/cwd"
226 }
227 return ""
228}
229
Patrice Arruda05ab2d02020-12-12 06:24:26 +0000230func (context *bazelContext) issueBazelCommand(runName bazel.RunName, command string, labels []string,
Chris Parsonsf3c96ef2020-09-29 02:23:17 -0400231 extraFlags ...string) (string, error) {
232
Jingwen Chen7c6089a2020-11-02 02:56:20 -0500233 cmdFlags := []string{"--output_base=" + context.outputBase, command}
Chris Parsonsf3c96ef2020-09-29 02:23:17 -0400234 cmdFlags = append(cmdFlags, labels...)
Chris Parsons8ccdb632020-11-17 15:41:01 -0500235 cmdFlags = append(cmdFlags, "--package_path=%workspace%/"+context.intermediatesDir())
Patrice Arruda05ab2d02020-12-12 06:24:26 +0000236 cmdFlags = append(cmdFlags, "--profile="+shared.BazelMetricsFilename(context, runName))
Chris Parsonsf3c96ef2020-09-29 02:23:17 -0400237 cmdFlags = append(cmdFlags, extraFlags...)
238
239 bazelCmd := exec.Command(context.bazelPath, cmdFlags...)
240 bazelCmd.Dir = context.workspaceDir
241 bazelCmd.Env = append(os.Environ(), "HOME="+context.homeDir, pwdPrefix())
242
Colin Crossff0278b2020-10-09 19:24:15 -0700243 stderr := &bytes.Buffer{}
244 bazelCmd.Stderr = stderr
Chris Parsonsf3c96ef2020-09-29 02:23:17 -0400245
246 if output, err := bazelCmd.Output(); err != nil {
247 return "", fmt.Errorf("bazel command failed. command: [%s], error [%s]", bazelCmd, stderr)
248 } else {
249 return string(output), nil
250 }
251}
252
Chris Parsons8ccdb632020-11-17 15:41:01 -0500253// Returns the string contents of a workspace file that should be output
254// adjacent to the main bzl file and build file.
255// This workspace file allows, via local_repository rule, sourcetree-level
256// BUILD targets to be referenced via @sourceroot.
257func (context *bazelContext) workspaceFileContents() []byte {
258 formatString := `
259# This file is generated by soong_build. Do not edit.
260local_repository(
261 name = "sourceroot",
262 path = "%s",
263)
264`
265 return []byte(fmt.Sprintf(formatString, context.workspaceDir))
266}
267
Chris Parsonsb0f8ac42020-10-23 16:48:08 -0400268func (context *bazelContext) mainBzlFileContents() []byte {
269 contents := `
Chris Parsonsdbcb1ff2020-12-10 17:19:18 -0500270#####################################################
Chris Parsonsb0f8ac42020-10-23 16:48:08 -0400271# This file is generated by soong_build. Do not edit.
Chris Parsonsdbcb1ff2020-12-10 17:19:18 -0500272#####################################################
273
Chris Parsonsb0f8ac42020-10-23 16:48:08 -0400274def _mixed_build_root_impl(ctx):
275 return [DefaultInfo(files = depset(ctx.files.deps))]
276
Chris Parsonsdbcb1ff2020-12-10 17:19:18 -0500277# Rule representing the root of the build, to depend on all Bazel targets that
278# are required for the build. Building this target will build the entire Bazel
279# build tree.
Chris Parsonsb0f8ac42020-10-23 16:48:08 -0400280mixed_build_root = rule(
281 implementation = _mixed_build_root_impl,
282 attrs = {"deps" : attr.label_list()},
283)
Chris Parsonsdbcb1ff2020-12-10 17:19:18 -0500284
285def _phony_root_impl(ctx):
286 return []
287
288# Rule to depend on other targets but build nothing.
289# This is useful as follows: building a target of this rule will generate
290# symlink forests for all dependencies of the target, without executing any
291# actions of the build.
292phony_root = rule(
293 implementation = _phony_root_impl,
294 attrs = {"deps" : attr.label_list()},
295)
Chris Parsonsb0f8ac42020-10-23 16:48:08 -0400296`
297 return []byte(contents)
298}
299
Chris Parsons8ccdb632020-11-17 15:41:01 -0500300// Returns a "canonicalized" corresponding to the given sourcetree-level label.
301// This abstraction is required because a sourcetree label such as //foo/bar:baz
302// must be referenced via the local repository prefix, such as
303// @sourceroot//foo/bar:baz.
304func canonicalizeLabel(label string) string {
305 if strings.HasPrefix(label, "//") {
306 return "@sourceroot" + label
307 } else {
308 return "@sourceroot//" + label
309 }
310}
311
Chris Parsonsb0f8ac42020-10-23 16:48:08 -0400312func (context *bazelContext) mainBuildFileContents() []byte {
313 formatString := `
314# This file is generated by soong_build. Do not edit.
Chris Parsonsdbcb1ff2020-12-10 17:19:18 -0500315load(":main.bzl", "mixed_build_root", "phony_root")
Chris Parsonsb0f8ac42020-10-23 16:48:08 -0400316
317mixed_build_root(name = "buildroot",
318 deps = [%s],
319)
Chris Parsonsdbcb1ff2020-12-10 17:19:18 -0500320
321phony_root(name = "phonyroot",
322 deps = [":buildroot"],
323)
Chris Parsonsb0f8ac42020-10-23 16:48:08 -0400324`
325 var buildRootDeps []string = nil
326 for val, _ := range context.requests {
Chris Parsons8ccdb632020-11-17 15:41:01 -0500327 buildRootDeps = append(buildRootDeps, fmt.Sprintf("\"%s\"", canonicalizeLabel(val.label)))
Chris Parsonsb0f8ac42020-10-23 16:48:08 -0400328 }
329 buildRootDepsString := strings.Join(buildRootDeps, ",\n ")
330
331 return []byte(fmt.Sprintf(formatString, buildRootDepsString))
332}
333
334func (context *bazelContext) cqueryStarlarkFileContents() []byte {
335 formatString := `
336# This file is generated by soong_build. Do not edit.
337getAllFilesLabels = {
338 %s
339}
340
341def format(target):
342 if str(target.label) in getAllFilesLabels:
343 return str(target.label) + ">>" + ', '.join([f.path for f in target.files.to_list()])
344 else:
345 # This target was not requested via cquery, and thus must be a dependency
346 # of a requested target.
347 return ""
348`
349 var buildRootDeps []string = nil
350 // TODO(cparsons): Sort by request type instead of assuming all requests
351 // are of GetAllFiles type.
352 for val, _ := range context.requests {
Chris Parsons8ccdb632020-11-17 15:41:01 -0500353 buildRootDeps = append(buildRootDeps, fmt.Sprintf("\"%s\" : True", canonicalizeLabel(val.label)))
Chris Parsonsb0f8ac42020-10-23 16:48:08 -0400354 }
355 buildRootDepsString := strings.Join(buildRootDeps, ",\n ")
356
357 return []byte(fmt.Sprintf(formatString, buildRootDepsString))
358}
359
Chris Parsons8ccdb632020-11-17 15:41:01 -0500360// Returns a workspace-relative path containing build-related metadata required
361// for interfacing with Bazel. Example: out/soong/bazel.
362func (context *bazelContext) intermediatesDir() string {
363 return filepath.Join(context.buildDir, "bazel")
364}
365
Chris Parsonsf3c96ef2020-09-29 02:23:17 -0400366// Issues commands to Bazel to receive results for all cquery requests
367// queued in the BazelContext.
368func (context *bazelContext) InvokeBazel() error {
369 context.results = make(map[cqueryKey]string)
370
Chris Parsonsf3c96ef2020-09-29 02:23:17 -0400371 var cqueryOutput string
372 var err error
Chris Parsons8ccdb632020-11-17 15:41:01 -0500373
Chris Parsons07c1e4a2021-01-19 17:19:16 -0500374 intermediatesDirPath := absolutePath(context.intermediatesDir())
375 if _, err := os.Stat(intermediatesDirPath); os.IsNotExist(err) {
376 err = os.Mkdir(intermediatesDirPath, 0777)
377 }
378
Chris Parsons8ccdb632020-11-17 15:41:01 -0500379 if err != nil {
380 return err
381 }
Chris Parsonsb0f8ac42020-10-23 16:48:08 -0400382 err = ioutil.WriteFile(
Chris Parsons8ccdb632020-11-17 15:41:01 -0500383 absolutePath(filepath.Join(context.intermediatesDir(), "main.bzl")),
Chris Parsonsb0f8ac42020-10-23 16:48:08 -0400384 context.mainBzlFileContents(), 0666)
385 if err != nil {
386 return err
387 }
388 err = ioutil.WriteFile(
Chris Parsons8ccdb632020-11-17 15:41:01 -0500389 absolutePath(filepath.Join(context.intermediatesDir(), "BUILD.bazel")),
Chris Parsonsb0f8ac42020-10-23 16:48:08 -0400390 context.mainBuildFileContents(), 0666)
391 if err != nil {
392 return err
393 }
Jaewoong Jung18aefc12020-12-21 09:11:10 -0800394 cqueryFileRelpath := filepath.Join(context.intermediatesDir(), "buildroot.cquery")
Chris Parsonsb0f8ac42020-10-23 16:48:08 -0400395 err = ioutil.WriteFile(
Jaewoong Jung18aefc12020-12-21 09:11:10 -0800396 absolutePath(cqueryFileRelpath),
Chris Parsonsb0f8ac42020-10-23 16:48:08 -0400397 context.cqueryStarlarkFileContents(), 0666)
398 if err != nil {
399 return err
400 }
Jaewoong Jung18aefc12020-12-21 09:11:10 -0800401 workspaceFileRelpath := filepath.Join(context.intermediatesDir(), "WORKSPACE.bazel")
Chris Parsons8ccdb632020-11-17 15:41:01 -0500402 err = ioutil.WriteFile(
Jaewoong Jung18aefc12020-12-21 09:11:10 -0800403 absolutePath(workspaceFileRelpath),
Chris Parsons8ccdb632020-11-17 15:41:01 -0500404 context.workspaceFileContents(), 0666)
405 if err != nil {
406 return err
407 }
Jaewoong Jung18aefc12020-12-21 09:11:10 -0800408 buildrootLabel := "//:buildroot"
Patrice Arruda05ab2d02020-12-12 06:24:26 +0000409 cqueryOutput, err = context.issueBazelCommand(bazel.CqueryBuildRootRunName, "cquery",
Jaewoong Jung18aefc12020-12-21 09:11:10 -0800410 []string{fmt.Sprintf("deps(%s)", buildrootLabel)},
Chris Parsonsb0f8ac42020-10-23 16:48:08 -0400411 "--output=starlark",
Jaewoong Jung18aefc12020-12-21 09:11:10 -0800412 "--starlark:file="+cqueryFileRelpath)
Chris Parsonsb0f8ac42020-10-23 16:48:08 -0400413
414 if err != nil {
415 return err
416 }
417
418 cqueryResults := map[string]string{}
419 for _, outputLine := range strings.Split(cqueryOutput, "\n") {
420 if strings.Contains(outputLine, ">>") {
421 splitLine := strings.SplitN(outputLine, ">>", 2)
422 cqueryResults[splitLine[0]] = splitLine[1]
423 }
424 }
425
Chris Parsonsf3c96ef2020-09-29 02:23:17 -0400426 for val, _ := range context.requests {
Chris Parsons8ccdb632020-11-17 15:41:01 -0500427 if cqueryResult, ok := cqueryResults[canonicalizeLabel(val.label)]; ok {
Chris Parsonsb0f8ac42020-10-23 16:48:08 -0400428 context.results[val] = string(cqueryResult)
Chris Parsonsf3c96ef2020-09-29 02:23:17 -0400429 } else {
Chris Parsonsb0f8ac42020-10-23 16:48:08 -0400430 return fmt.Errorf("missing result for bazel target %s", val.label)
Chris Parsonsf3c96ef2020-09-29 02:23:17 -0400431 }
432 }
433
Chris Parsonsdbcb1ff2020-12-10 17:19:18 -0500434 // Issue an aquery command to retrieve action information about the bazel build tree.
435 //
Chris Parsonsf3c96ef2020-09-29 02:23:17 -0400436 // TODO(cparsons): Use --target_pattern_file to avoid command line limits.
Chris Parsonsdbcb1ff2020-12-10 17:19:18 -0500437 var aqueryOutput string
438 aqueryOutput, err = context.issueBazelCommand(bazel.AqueryBuildRootRunName, "aquery",
Jaewoong Jung18aefc12020-12-21 09:11:10 -0800439 []string{fmt.Sprintf("deps(%s)", buildrootLabel),
Chris Parsonsdbcb1ff2020-12-10 17:19:18 -0500440 // Use jsonproto instead of proto; actual proto parsing would require a dependency on Bazel's
441 // proto sources, which would add a number of unnecessary dependencies.
442 "--output=jsonproto"})
Chris Parsonsf3c96ef2020-09-29 02:23:17 -0400443
444 if err != nil {
445 return err
446 }
447
Chris Parsons4f069892021-01-15 12:22:41 -0500448 context.buildStatements, err = bazel.AqueryBuildStatements([]byte(aqueryOutput))
449 if err != nil {
450 return err
451 }
Chris Parsonsdbcb1ff2020-12-10 17:19:18 -0500452
453 // Issue a build command of the phony root to generate symlink forests for dependencies of the
454 // Bazel build. This is necessary because aquery invocations do not generate this symlink forest,
455 // but some of symlinks may be required to resolve source dependencies of the build.
456 _, err = context.issueBazelCommand(bazel.BazelBuildPhonyRootRunName, "build",
457 []string{"//:phonyroot"})
458
459 if err != nil {
460 return err
461 }
462
463 fmt.Printf("Build statements %s", context.buildStatements)
Chris Parsonsf3c96ef2020-09-29 02:23:17 -0400464 // Clear requests.
465 context.requests = map[cqueryKey]bool{}
466 return nil
467}
Chris Parsonsa798d962020-10-12 23:44:08 -0400468
Chris Parsonsdbcb1ff2020-12-10 17:19:18 -0500469func (context *bazelContext) BuildStatementsToRegister() []bazel.BuildStatement {
470 return context.buildStatements
471}
472
473func (context *bazelContext) OutputBase() string {
474 return context.outputBase
475}
476
Chris Parsonsa798d962020-10-12 23:44:08 -0400477// Singleton used for registering BUILD file ninja dependencies (needed
478// for correctness of builds which use Bazel.
479func BazelSingleton() Singleton {
480 return &bazelSingleton{}
481}
482
483type bazelSingleton struct{}
484
485func (c *bazelSingleton) GenerateBuildActions(ctx SingletonContext) {
Chris Parsonsdbcb1ff2020-12-10 17:19:18 -0500486 // bazelSingleton is a no-op if mixed-soong-bazel-builds are disabled.
487 if !ctx.Config().BazelContext.BazelEnabled() {
488 return
489 }
Chris Parsonsa798d962020-10-12 23:44:08 -0400490
Chris Parsonsdbcb1ff2020-12-10 17:19:18 -0500491 // Add ninja file dependencies for files which all bazel invocations require.
492 bazelBuildList := absolutePath(filepath.Join(
493 filepath.Dir(bootstrap.ModuleListFile), "bazel.list"))
494 ctx.AddNinjaFileDeps(bazelBuildList)
495
496 data, err := ioutil.ReadFile(bazelBuildList)
497 if err != nil {
498 ctx.Errorf(err.Error())
499 }
500 files := strings.Split(strings.TrimSpace(string(data)), "\n")
501 for _, file := range files {
502 ctx.AddNinjaFileDeps(file)
503 }
504
505 // Register bazel-owned build statements (obtained from the aquery invocation).
506 for index, buildStatement := range ctx.Config().BazelContext.BuildStatementsToRegister() {
507 rule := NewRuleBuilder(pctx, ctx)
508 cmd := rule.Command()
509 cmd.Text(fmt.Sprintf("cd %s/execroot/__main__ && %s",
510 ctx.Config().BazelContext.OutputBase(), buildStatement.Command))
511
512 for _, outputPath := range buildStatement.OutputPaths {
513 cmd.ImplicitOutput(PathForBazelOut(ctx, outputPath))
Chris Parsonsa798d962020-10-12 23:44:08 -0400514 }
Chris Parsonsdbcb1ff2020-12-10 17:19:18 -0500515 for _, inputPath := range buildStatement.InputPaths {
516 cmd.Implicit(PathForBazelOut(ctx, inputPath))
Chris Parsonsa798d962020-10-12 23:44:08 -0400517 }
Chris Parsonsdbcb1ff2020-12-10 17:19:18 -0500518
519 // This is required to silence warnings pertaining to unexpected timestamps. Particularly,
520 // some Bazel builtins (such as files in the bazel_tools directory) have far-future
521 // timestamps. Without restat, Ninja would emit warnings that the input files of a
522 // build statement have later timestamps than the outputs.
523 rule.Restat()
524
Liz Kammer13548d72020-12-16 11:13:30 -0800525 rule.Build(fmt.Sprintf("bazel %d", index), buildStatement.Mnemonic)
Chris Parsonsa798d962020-10-12 23:44:08 -0400526 }
527}