blob: b22cb286178461f4833dbf3aad3b4efdc7e53163 [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)
Jingwen Chenbf61afb2021-05-06 13:31:18 +000083 writeFiles(ctx, bp2buildDir, bp2buildFiles)
Chris Parsons520e88b2023-02-09 17:54:00 -050084 // Delete files under the bp2build root which weren't just written. An
85 // alternative would have been to delete the whole directory and write these
86 // files. However, this would regenerate files which were otherwise unchanged
87 // since the last bp2build run, which would have negative incremental
88 // performance implications.
89 deleteFilesExcept(ctx, bp2buildDir, bp2buildFiles)
Liz Kammer2dd9ca42020-11-25 16:06:39 -080090
Cole Faust9e384e22023-02-08 17:43:09 -080091 injectionFiles, err := CreateSoongInjectionDirFiles(ctx, res.metrics)
92 if err != nil {
93 fmt.Printf("%s\n", err.Error())
94 os.Exit(1)
95 }
96 writeFiles(ctx, android.PathForOutput(ctx, bazel.SoongInjectionDirName), injectionFiles)
Cole Faustc9508aa2023-02-07 11:38:27 -080097 starlarkDeps, err := starlark_import.GetNinjaDeps()
98 if err != nil {
99 fmt.Fprintf(os.Stderr, "%s\n", err)
100 os.Exit(1)
101 }
102 ctx.AddNinjaFileDeps(starlarkDeps...)
Spandan Das83e787e2023-01-11 02:50:00 +0000103 return &res.metrics
104}
105
106// Wrapper function that will be responsible for all files in soong_injection directory
107// This includes
108// 1. config value(s) that are hardcoded in Soong
109// 2. product_config variables
Cole Faust9e384e22023-02-08 17:43:09 -0800110func CreateSoongInjectionDirFiles(ctx *CodegenContext, metrics CodegenMetrics) ([]BazelFile, error) {
Spandan Das83e787e2023-01-11 02:50:00 +0000111 var ret []BazelFile
112
Cole Faustb85d1a12022-11-08 18:14:01 -0800113 productConfigFiles, err := CreateProductConfigFiles(ctx)
114 if err != nil {
Cole Faust9e384e22023-02-08 17:43:09 -0800115 return nil, err
Cole Faustb85d1a12022-11-08 18:14:01 -0800116 }
Spandan Das83e787e2023-01-11 02:50:00 +0000117 ret = append(ret, productConfigFiles...)
Cole Faust9e384e22023-02-08 17:43:09 -0800118 injectionFiles, err := soongInjectionFiles(ctx.Config(), metrics)
119 if err != nil {
120 return nil, err
121 }
122 ret = append(ret, injectionFiles...)
123 return ret, nil
Liz Kammer2dd9ca42020-11-25 16:06:39 -0800124}
125
Jingwen Chen12b4c272021-03-10 02:05:59 -0500126// Get the output directory and create it if it doesn't exist.
127func getOrCreateOutputDir(outputDir android.OutputPath, ctx android.PathContext, dir string) android.OutputPath {
128 dirPath := outputDir.Join(ctx, dir)
Usta Shresthadb46a9b2022-07-11 11:29:56 -0400129 if err := android.CreateOutputDirIfNonexistent(dirPath, os.ModePerm); err != nil {
130 fmt.Printf("ERROR: path %s: %s", dirPath, err.Error())
131 }
Jingwen Chen12b4c272021-03-10 02:05:59 -0500132 return dirPath
Liz Kammer2dd9ca42020-11-25 16:06:39 -0800133}
134
Jingwen Chenbf61afb2021-05-06 13:31:18 +0000135// writeFiles materializes a list of BazelFile rooted at outputDir.
136func writeFiles(ctx android.PathContext, outputDir android.OutputPath, files []BazelFile) {
137 for _, f := range files {
138 p := getOrCreateOutputDir(outputDir, ctx, f.Dir).Join(ctx, f.Basename)
Usta Shresthadb46a9b2022-07-11 11:29:56 -0400139 if err := writeFile(p, f.Contents); err != nil {
Jingwen Chenbf61afb2021-05-06 13:31:18 +0000140 panic(fmt.Errorf("Failed to write %q (dir %q) due to %q", f.Basename, f.Dir, err))
141 }
142 }
143}
144
Usta Shresthadb46a9b2022-07-11 11:29:56 -0400145func writeFile(pathToFile android.OutputPath, content string) error {
Jingwen Chen12b4c272021-03-10 02:05:59 -0500146 // These files are made editable to allow users to modify and iterate on them
147 // in the source tree.
148 return android.WriteFileToOutputDir(pathToFile, []byte(content), 0644)
Liz Kammer2dd9ca42020-11-25 16:06:39 -0800149}