blob: cfe52db47017f68e85babd0a9795e8f396c5db5c [file] [log] [blame]
Liz Kammer2dd9ca42020-11-25 16:06:39 -08001// 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 bp2build
16
17import (
Cole Faustc9508aa2023-02-07 11:38:27 -080018 "android/soong/starlark_import"
Jingwen Chendaa54bc2020-12-14 02:58:54 -050019 "fmt"
Liz Kammer2dd9ca42020-11-25 16:06:39 -080020 "os"
Chris Parsons520e88b2023-02-09 17:54:00 -050021 "path/filepath"
Liz Kammer6eff3232021-08-26 08:37:59 -040022 "strings"
Chris Parsons3b1f83d2021-10-14 14:08:38 -040023
24 "android/soong/android"
25 "android/soong/bazel"
Chris Parsons520e88b2023-02-09 17:54:00 -050026 "android/soong/shared"
Liz Kammer2dd9ca42020-11-25 16:06:39 -080027)
28
Chris Parsons520e88b2023-02-09 17:54:00 -050029func deleteFilesExcept(ctx *CodegenContext, rootOutputPath android.OutputPath, except []BazelFile) {
30 // Delete files that should no longer be present.
31 bp2buildDirAbs := shared.JoinPath(ctx.topDir, rootOutputPath.String())
32
33 filesToDelete := make(map[string]struct{})
34 err := filepath.Walk(bp2buildDirAbs,
35 func(path string, info os.FileInfo, err error) error {
36 if err != nil {
37 return err
38 }
39 if !info.IsDir() {
40 relPath, err := filepath.Rel(bp2buildDirAbs, path)
41 if err != nil {
42 return err
43 }
44 filesToDelete[relPath] = struct{}{}
45 }
46 return nil
47 })
48 if err != nil {
49 fmt.Printf("ERROR reading %s: %s", bp2buildDirAbs, err)
50 os.Exit(1)
51 }
52
53 for _, bazelFile := range except {
54 filePath := filepath.Join(bazelFile.Dir, bazelFile.Basename)
55 delete(filesToDelete, filePath)
56 }
57 for f, _ := range filesToDelete {
58 absPath := shared.JoinPath(bp2buildDirAbs, f)
59 if err := os.RemoveAll(absPath); err != nil {
60 fmt.Printf("ERROR deleting %s: %s", absPath, err)
61 os.Exit(1)
62 }
63 }
64}
65
Jingwen Chen12b4c272021-03-10 02:05:59 -050066// Codegen is the backend of bp2build. The code generator is responsible for
67// writing .bzl files that are equivalent to Android.bp files that are capable
68// of being built with Bazel.
usta4f5d2c12022-10-28 23:32:01 -040069func Codegen(ctx *CodegenContext) *CodegenMetrics {
Jingwen Chenbf61afb2021-05-06 13:31:18 +000070 // This directory stores BUILD files that could be eventually checked-in.
71 bp2buildDir := android.PathForOutput(ctx, "bp2build")
Liz Kammer2dd9ca42020-11-25 16:06:39 -080072
Liz Kammer6eff3232021-08-26 08:37:59 -040073 res, errs := GenerateBazelTargets(ctx, true)
74 if len(errs) > 0 {
75 errMsgs := make([]string, len(errs))
76 for i, err := range errs {
77 errMsgs[i] = fmt.Sprintf("%q", err)
78 }
79 fmt.Printf("ERROR: Encountered %d error(s): \nERROR: %s", len(errs), strings.Join(errMsgs, "\n"))
80 os.Exit(1)
81 }
Sasha Smundak0fd93e02022-05-19 19:34:31 -070082 bp2buildFiles := CreateBazelFiles(ctx.Config(), nil, res.buildFileToTargets, ctx.mode)
Cole Faustf8231dd2023-04-21 17:37:11 -070083 injectionFiles, additionalBp2buildFiles, err := CreateSoongInjectionDirFiles(ctx, res.metrics)
84 if err != nil {
85 fmt.Printf("%s\n", err.Error())
86 os.Exit(1)
87 }
88 bp2buildFiles = append(bp2buildFiles, additionalBp2buildFiles...)
Jingwen Chenbf61afb2021-05-06 13:31:18 +000089 writeFiles(ctx, bp2buildDir, bp2buildFiles)
Chris Parsons520e88b2023-02-09 17:54:00 -050090 // Delete files under the bp2build root which weren't just written. An
91 // alternative would have been to delete the whole directory and write these
92 // files. However, this would regenerate files which were otherwise unchanged
93 // since the last bp2build run, which would have negative incremental
94 // performance implications.
95 deleteFilesExcept(ctx, bp2buildDir, bp2buildFiles)
Liz Kammer2dd9ca42020-11-25 16:06:39 -080096
Cole Faust9e384e22023-02-08 17:43:09 -080097 writeFiles(ctx, android.PathForOutput(ctx, bazel.SoongInjectionDirName), injectionFiles)
Cole Faustc9508aa2023-02-07 11:38:27 -080098 starlarkDeps, err := starlark_import.GetNinjaDeps()
99 if err != nil {
100 fmt.Fprintf(os.Stderr, "%s\n", err)
101 os.Exit(1)
102 }
103 ctx.AddNinjaFileDeps(starlarkDeps...)
Spandan Das83e787e2023-01-11 02:50:00 +0000104 return &res.metrics
105}
106
107// Wrapper function that will be responsible for all files in soong_injection directory
108// This includes
109// 1. config value(s) that are hardcoded in Soong
110// 2. product_config variables
Cole Faustf8231dd2023-04-21 17:37:11 -0700111func CreateSoongInjectionDirFiles(ctx *CodegenContext, metrics CodegenMetrics) ([]BazelFile, []BazelFile, error) {
Spandan Das83e787e2023-01-11 02:50:00 +0000112 var ret []BazelFile
113
Cole Faustf8231dd2023-04-21 17:37:11 -0700114 productConfigInjectionFiles, productConfigBp2BuildDirFiles, err := CreateProductConfigFiles(ctx)
Cole Faustb85d1a12022-11-08 18:14:01 -0800115 if err != nil {
Cole Faustf8231dd2023-04-21 17:37:11 -0700116 return nil, nil, err
Cole Faustb85d1a12022-11-08 18:14:01 -0800117 }
Cole Faustf8231dd2023-04-21 17:37:11 -0700118 ret = append(ret, productConfigInjectionFiles...)
Cole Faust9e384e22023-02-08 17:43:09 -0800119 injectionFiles, err := soongInjectionFiles(ctx.Config(), metrics)
120 if err != nil {
Cole Faustf8231dd2023-04-21 17:37:11 -0700121 return nil, nil, err
Cole Faust9e384e22023-02-08 17:43:09 -0800122 }
Cole Faustf8231dd2023-04-21 17:37:11 -0700123 ret = append(injectionFiles, ret...)
124 return ret, productConfigBp2BuildDirFiles, nil
Liz Kammer2dd9ca42020-11-25 16:06:39 -0800125}
126
Jingwen Chen12b4c272021-03-10 02:05:59 -0500127// Get the output directory and create it if it doesn't exist.
128func getOrCreateOutputDir(outputDir android.OutputPath, ctx android.PathContext, dir string) android.OutputPath {
129 dirPath := outputDir.Join(ctx, dir)
Usta Shresthadb46a9b2022-07-11 11:29:56 -0400130 if err := android.CreateOutputDirIfNonexistent(dirPath, os.ModePerm); err != nil {
131 fmt.Printf("ERROR: path %s: %s", dirPath, err.Error())
132 }
Jingwen Chen12b4c272021-03-10 02:05:59 -0500133 return dirPath
Liz Kammer2dd9ca42020-11-25 16:06:39 -0800134}
135
Jingwen Chenbf61afb2021-05-06 13:31:18 +0000136// writeFiles materializes a list of BazelFile rooted at outputDir.
137func writeFiles(ctx android.PathContext, outputDir android.OutputPath, files []BazelFile) {
138 for _, f := range files {
139 p := getOrCreateOutputDir(outputDir, ctx, f.Dir).Join(ctx, f.Basename)
Usta Shresthadb46a9b2022-07-11 11:29:56 -0400140 if err := writeFile(p, f.Contents); err != nil {
Jingwen Chenbf61afb2021-05-06 13:31:18 +0000141 panic(fmt.Errorf("Failed to write %q (dir %q) due to %q", f.Basename, f.Dir, err))
142 }
143 }
144}
145
Usta Shresthadb46a9b2022-07-11 11:29:56 -0400146func writeFile(pathToFile android.OutputPath, content string) error {
Jingwen Chen12b4c272021-03-10 02:05:59 -0500147 // These files are made editable to allow users to modify and iterate on them
148 // in the source tree.
149 return android.WriteFileToOutputDir(pathToFile, []byte(content), 0644)
Liz Kammer2dd9ca42020-11-25 16:06:39 -0800150}