Kadir Çetinkaya | 0769200 | 2024-02-28 07:10:05 +0000 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2024 The Android Open Source Project |
| 3 | * |
| 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | * you may not use this file except in compliance with the License. |
| 6 | * You may obtain a copy of the License at |
| 7 | * |
| 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | * |
| 10 | * Unless required by applicable law or agreed to in writing, software |
| 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | * See the License for the specific language governing permissions and |
| 14 | * limitations under the License. |
| 15 | */ |
| 16 | |
Michael Merg | 6bafd75 | 2024-02-12 13:52:00 +0000 | [diff] [blame] | 17 | // Binary ide_query generates and analyzes build artifacts. |
| 18 | // The produced result can be consumed by IDEs to provide language features. |
| 19 | package main |
| 20 | |
| 21 | import ( |
Kadir Çetinkaya | 0769200 | 2024-02-28 07:10:05 +0000 | [diff] [blame] | 22 | "bytes" |
Michael Merg | 6bafd75 | 2024-02-12 13:52:00 +0000 | [diff] [blame] | 23 | "container/list" |
| 24 | "context" |
| 25 | "encoding/json" |
| 26 | "flag" |
| 27 | "fmt" |
| 28 | "log" |
| 29 | "os" |
| 30 | "os/exec" |
| 31 | "path" |
| 32 | "slices" |
| 33 | "strings" |
| 34 | |
| 35 | "google.golang.org/protobuf/proto" |
Michael Merg | 86cca74 | 2024-06-11 15:24:05 +0000 | [diff] [blame] | 36 | apb "ide_query/cc_analyzer_proto" |
Michael Merg | 6bafd75 | 2024-02-12 13:52:00 +0000 | [diff] [blame] | 37 | pb "ide_query/ide_query_proto" |
| 38 | ) |
| 39 | |
| 40 | // Env contains information about the current environment. |
| 41 | type Env struct { |
Kadir Çetinkaya | 0769200 | 2024-02-28 07:10:05 +0000 | [diff] [blame] | 42 | LunchTarget LunchTarget |
| 43 | RepoDir string |
| 44 | OutDir string |
| 45 | ClangToolsRoot string |
Michael Merg | 6bafd75 | 2024-02-12 13:52:00 +0000 | [diff] [blame] | 46 | } |
| 47 | |
| 48 | // LunchTarget is a parsed Android lunch target. |
| 49 | // Input format: <product_name>-<release_type>-<build_variant> |
| 50 | type LunchTarget struct { |
| 51 | Product string |
| 52 | Release string |
| 53 | Variant string |
| 54 | } |
| 55 | |
| 56 | var _ flag.Value = (*LunchTarget)(nil) |
| 57 | |
| 58 | // // Get implements flag.Value. |
| 59 | // func (l *LunchTarget) Get() any { |
| 60 | // return l |
| 61 | // } |
| 62 | |
| 63 | // Set implements flag.Value. |
| 64 | func (l *LunchTarget) Set(s string) error { |
| 65 | parts := strings.Split(s, "-") |
| 66 | if len(parts) != 3 { |
| 67 | return fmt.Errorf("invalid lunch target: %q, must have form <product_name>-<release_type>-<build_variant>", s) |
| 68 | } |
| 69 | *l = LunchTarget{ |
| 70 | Product: parts[0], |
| 71 | Release: parts[1], |
| 72 | Variant: parts[2], |
| 73 | } |
| 74 | return nil |
| 75 | } |
| 76 | |
| 77 | // String implements flag.Value. |
| 78 | func (l *LunchTarget) String() string { |
| 79 | return fmt.Sprintf("%s-%s-%s", l.Product, l.Release, l.Variant) |
| 80 | } |
| 81 | |
| 82 | func main() { |
| 83 | var env Env |
Michael Merg | 86cca74 | 2024-06-11 15:24:05 +0000 | [diff] [blame] | 84 | env.OutDir = strings.TrimSuffix(os.Getenv("OUT_DIR"), "/") |
Michael Merg | 6bafd75 | 2024-02-12 13:52:00 +0000 | [diff] [blame] | 85 | env.RepoDir = os.Getenv("ANDROID_BUILD_TOP") |
Kadir Çetinkaya | 0769200 | 2024-02-28 07:10:05 +0000 | [diff] [blame] | 86 | env.ClangToolsRoot = os.Getenv("PREBUILTS_CLANG_TOOLS_ROOT") |
Michael Merg | 6bafd75 | 2024-02-12 13:52:00 +0000 | [diff] [blame] | 87 | flag.Var(&env.LunchTarget, "lunch_target", "The lunch target to query") |
| 88 | flag.Parse() |
| 89 | files := flag.Args() |
| 90 | if len(files) == 0 { |
| 91 | fmt.Println("No files provided.") |
| 92 | os.Exit(1) |
| 93 | return |
| 94 | } |
| 95 | |
Michael Merg | 86cca74 | 2024-06-11 15:24:05 +0000 | [diff] [blame] | 96 | var ccFiles, javaFiles []string |
Michael Merg | 6bafd75 | 2024-02-12 13:52:00 +0000 | [diff] [blame] | 97 | for _, f := range files { |
| 98 | switch { |
| 99 | case strings.HasSuffix(f, ".java") || strings.HasSuffix(f, ".kt"): |
Michael Merg | 86cca74 | 2024-06-11 15:24:05 +0000 | [diff] [blame] | 100 | javaFiles = append(javaFiles, f) |
Kadir Çetinkaya | 0769200 | 2024-02-28 07:10:05 +0000 | [diff] [blame] | 101 | case strings.HasSuffix(f, ".cc") || strings.HasSuffix(f, ".cpp") || strings.HasSuffix(f, ".h"): |
Michael Merg | 86cca74 | 2024-06-11 15:24:05 +0000 | [diff] [blame] | 102 | ccFiles = append(ccFiles, f) |
Michael Merg | 6bafd75 | 2024-02-12 13:52:00 +0000 | [diff] [blame] | 103 | default: |
| 104 | log.Printf("File %q is supported - will be skipped.", f) |
| 105 | } |
| 106 | } |
| 107 | |
| 108 | ctx := context.Background() |
Kadir Çetinkaya | 0769200 | 2024-02-28 07:10:05 +0000 | [diff] [blame] | 109 | // TODO(michaelmerg): Figure out if module_bp_java_deps.json and compile_commands.json is outdated. |
Michael Merg | 6bafd75 | 2024-02-12 13:52:00 +0000 | [diff] [blame] | 110 | runMake(ctx, env, "nothing") |
| 111 | |
Michael Merg | 86cca74 | 2024-06-11 15:24:05 +0000 | [diff] [blame] | 112 | javaModules, err := loadJavaModules(env) |
Michael Merg | 6bafd75 | 2024-02-12 13:52:00 +0000 | [diff] [blame] | 113 | if err != nil { |
Kadir Çetinkaya | 0769200 | 2024-02-28 07:10:05 +0000 | [diff] [blame] | 114 | log.Printf("Failed to load java modules: %v", err) |
| 115 | } |
Kadir Çetinkaya | 0769200 | 2024-02-28 07:10:05 +0000 | [diff] [blame] | 116 | |
Michael Merg | 86cca74 | 2024-06-11 15:24:05 +0000 | [diff] [blame] | 117 | var targets []string |
| 118 | javaTargetsByFile := findJavaModules(javaFiles, javaModules) |
| 119 | for _, t := range javaTargetsByFile { |
| 120 | targets = append(targets, t) |
Michael Merg | 6bafd75 | 2024-02-12 13:52:00 +0000 | [diff] [blame] | 121 | } |
| 122 | |
Michael Merg | 86cca74 | 2024-06-11 15:24:05 +0000 | [diff] [blame] | 123 | ccTargets, err := getCCTargets(ctx, env, ccFiles) |
| 124 | if err != nil { |
| 125 | log.Fatalf("Failed to query cc targets: %v", err) |
| 126 | } |
| 127 | targets = append(targets, ccTargets...) |
| 128 | if len(targets) == 0 { |
| 129 | fmt.Println("No targets found.") |
| 130 | os.Exit(1) |
| 131 | return |
| 132 | } |
Kadir Çetinkaya | 0769200 | 2024-02-28 07:10:05 +0000 | [diff] [blame] | 133 | |
Michael Merg | 86cca74 | 2024-06-11 15:24:05 +0000 | [diff] [blame] | 134 | fmt.Fprintf(os.Stderr, "Running make for modules: %v\n", strings.Join(targets, ", ")) |
| 135 | if err := runMake(ctx, env, targets...); err != nil { |
| 136 | log.Printf("Building modules failed: %v", err) |
| 137 | } |
| 138 | |
| 139 | var analysis pb.IdeAnalysis |
| 140 | results, units := getJavaInputs(env, javaTargetsByFile, javaModules) |
| 141 | analysis.Results = results |
| 142 | analysis.Units = units |
| 143 | if err != nil && analysis.Error == nil { |
| 144 | analysis.Error = &pb.AnalysisError{ |
| 145 | ErrorMessage: err.Error(), |
| 146 | } |
| 147 | } |
| 148 | |
| 149 | results, units, err = getCCInputs(ctx, env, ccFiles) |
| 150 | analysis.Results = append(analysis.Results, results...) |
| 151 | analysis.Units = append(analysis.Units, units...) |
| 152 | if err != nil && analysis.Error == nil { |
| 153 | analysis.Error = &pb.AnalysisError{ |
| 154 | ErrorMessage: err.Error(), |
| 155 | } |
| 156 | } |
| 157 | |
| 158 | analysis.BuildOutDir = env.OutDir |
| 159 | data, err := proto.Marshal(&analysis) |
Kadir Çetinkaya | 0769200 | 2024-02-28 07:10:05 +0000 | [diff] [blame] | 160 | if err != nil { |
| 161 | log.Fatalf("Failed to marshal result proto: %v", err) |
| 162 | } |
| 163 | |
Michael Merg | d8880ab | 2024-03-20 11:05:23 +0000 | [diff] [blame] | 164 | _, err = os.Stdout.Write(data) |
Kadir Çetinkaya | 0769200 | 2024-02-28 07:10:05 +0000 | [diff] [blame] | 165 | if err != nil { |
| 166 | log.Fatalf("Failed to write result proto: %v", err) |
| 167 | } |
| 168 | |
Michael Merg | 86cca74 | 2024-06-11 15:24:05 +0000 | [diff] [blame] | 169 | for _, r := range analysis.Results { |
| 170 | fmt.Fprintf(os.Stderr, "%s: %+v\n", r.GetSourceFilePath(), r.GetStatus()) |
Kadir Çetinkaya | 0769200 | 2024-02-28 07:10:05 +0000 | [diff] [blame] | 171 | } |
| 172 | } |
| 173 | |
Michael Merg | 86cca74 | 2024-06-11 15:24:05 +0000 | [diff] [blame] | 174 | func repoState(env Env, filePaths []string) *apb.RepoState { |
Kadir Çetinkaya | 0769200 | 2024-02-28 07:10:05 +0000 | [diff] [blame] | 175 | const compDbPath = "soong/development/ide/compdb/compile_commands.json" |
Michael Merg | 86cca74 | 2024-06-11 15:24:05 +0000 | [diff] [blame] | 176 | return &apb.RepoState{ |
Kadir Çetinkaya | 0769200 | 2024-02-28 07:10:05 +0000 | [diff] [blame] | 177 | RepoDir: env.RepoDir, |
Michael Merg | 86cca74 | 2024-06-11 15:24:05 +0000 | [diff] [blame] | 178 | ActiveFilePath: filePaths, |
Kadir Çetinkaya | 0769200 | 2024-02-28 07:10:05 +0000 | [diff] [blame] | 179 | OutDir: env.OutDir, |
| 180 | CompDbPath: path.Join(env.OutDir, compDbPath), |
| 181 | } |
| 182 | } |
| 183 | |
Michael Merg | 86cca74 | 2024-06-11 15:24:05 +0000 | [diff] [blame] | 184 | func runCCanalyzer(ctx context.Context, env Env, mode string, in []byte) ([]byte, error) { |
Kadir Çetinkaya | 0769200 | 2024-02-28 07:10:05 +0000 | [diff] [blame] | 185 | ccAnalyzerPath := path.Join(env.ClangToolsRoot, "bin/ide_query_cc_analyzer") |
| 186 | outBuffer := new(bytes.Buffer) |
| 187 | |
| 188 | inBuffer := new(bytes.Buffer) |
| 189 | inBuffer.Write(in) |
| 190 | |
| 191 | cmd := exec.CommandContext(ctx, ccAnalyzerPath, "--mode="+mode) |
| 192 | cmd.Dir = env.RepoDir |
| 193 | |
| 194 | cmd.Stdin = inBuffer |
| 195 | cmd.Stdout = outBuffer |
| 196 | cmd.Stderr = os.Stderr |
| 197 | |
| 198 | err := cmd.Run() |
| 199 | |
| 200 | return outBuffer.Bytes(), err |
| 201 | } |
| 202 | |
| 203 | // Execute cc_analyzer and get all the targets that needs to be build for analyzing files. |
Michael Merg | 86cca74 | 2024-06-11 15:24:05 +0000 | [diff] [blame] | 204 | func getCCTargets(ctx context.Context, env Env, filePaths []string) ([]string, error) { |
| 205 | state, err := proto.Marshal(repoState(env, filePaths)) |
Kadir Çetinkaya | 0769200 | 2024-02-28 07:10:05 +0000 | [diff] [blame] | 206 | if err != nil { |
| 207 | log.Fatalln("Failed to serialize state:", err) |
| 208 | } |
| 209 | |
Michael Merg | 86cca74 | 2024-06-11 15:24:05 +0000 | [diff] [blame] | 210 | resp := new(apb.DepsResponse) |
| 211 | result, err := runCCanalyzer(ctx, env, "deps", state) |
| 212 | if err != nil { |
| 213 | return nil, err |
| 214 | } |
| 215 | |
| 216 | if err := proto.Unmarshal(result, resp); err != nil { |
| 217 | return nil, fmt.Errorf("malformed response from cc_analyzer: %v", err) |
Michael Merg | 6bafd75 | 2024-02-12 13:52:00 +0000 | [diff] [blame] | 218 | } |
| 219 | |
Kadir Çetinkaya | 0769200 | 2024-02-28 07:10:05 +0000 | [diff] [blame] | 220 | var targets []string |
Michael Merg | 86cca74 | 2024-06-11 15:24:05 +0000 | [diff] [blame] | 221 | if resp.Status != nil && resp.Status.Code != apb.Status_OK { |
| 222 | return targets, fmt.Errorf("cc_analyzer failed: %v", resp.Status.Message) |
Michael Merg | 6bafd75 | 2024-02-12 13:52:00 +0000 | [diff] [blame] | 223 | } |
Michael Merg | 86cca74 | 2024-06-11 15:24:05 +0000 | [diff] [blame] | 224 | |
Kadir Çetinkaya | 0769200 | 2024-02-28 07:10:05 +0000 | [diff] [blame] | 225 | for _, deps := range resp.Deps { |
| 226 | targets = append(targets, deps.BuildTarget...) |
Michael Merg | 6bafd75 | 2024-02-12 13:52:00 +0000 | [diff] [blame] | 227 | } |
Michael Merg | 86cca74 | 2024-06-11 15:24:05 +0000 | [diff] [blame] | 228 | return targets, nil |
Kadir Çetinkaya | 0769200 | 2024-02-28 07:10:05 +0000 | [diff] [blame] | 229 | } |
| 230 | |
Michael Merg | 86cca74 | 2024-06-11 15:24:05 +0000 | [diff] [blame] | 231 | func getCCInputs(ctx context.Context, env Env, filePaths []string) ([]*pb.AnalysisResult, []*pb.BuildableUnit, error) { |
| 232 | state, err := proto.Marshal(repoState(env, filePaths)) |
Kadir Çetinkaya | 0769200 | 2024-02-28 07:10:05 +0000 | [diff] [blame] | 233 | if err != nil { |
| 234 | log.Fatalln("Failed to serialize state:", err) |
| 235 | } |
| 236 | |
Michael Merg | 86cca74 | 2024-06-11 15:24:05 +0000 | [diff] [blame] | 237 | resp := new(apb.IdeAnalysis) |
| 238 | result, err := runCCanalyzer(ctx, env, "inputs", state) |
| 239 | if err != nil { |
| 240 | return nil, nil, fmt.Errorf("cc_analyzer failed:", err) |
| 241 | } |
| 242 | if err := proto.Unmarshal(result, resp); err != nil { |
| 243 | return nil, nil, fmt.Errorf("malformed response from cc_analyzer: %v", err) |
| 244 | } |
| 245 | if resp.Status != nil && resp.Status.Code != apb.Status_OK { |
| 246 | return nil, nil, fmt.Errorf("cc_analyzer failed: %v", resp.Status.Message) |
Kadir Çetinkaya | 0769200 | 2024-02-28 07:10:05 +0000 | [diff] [blame] | 247 | } |
| 248 | |
Michael Merg | 86cca74 | 2024-06-11 15:24:05 +0000 | [diff] [blame] | 249 | var results []*pb.AnalysisResult |
| 250 | var units []*pb.BuildableUnit |
| 251 | for _, s := range resp.Sources { |
| 252 | status := &pb.AnalysisResult_Status{ |
| 253 | Code: pb.AnalysisResult_Status_CODE_OK, |
Kadir Çetinkaya | 0769200 | 2024-02-28 07:10:05 +0000 | [diff] [blame] | 254 | } |
Michael Merg | 86cca74 | 2024-06-11 15:24:05 +0000 | [diff] [blame] | 255 | if s.GetStatus().GetCode() != apb.Status_OK { |
| 256 | status.Code = pb.AnalysisResult_Status_CODE_BUILD_FAILED |
| 257 | status.StatusMessage = proto.String(s.GetStatus().GetMessage()) |
Michael Merg | 6bafd75 | 2024-02-12 13:52:00 +0000 | [diff] [blame] | 258 | } |
| 259 | |
Michael Merg | 86cca74 | 2024-06-11 15:24:05 +0000 | [diff] [blame] | 260 | result := &pb.AnalysisResult{ |
| 261 | SourceFilePath: s.GetPath(), |
| 262 | UnitId: s.GetPath(), |
| 263 | Status: status, |
Michael Merg | 6bafd75 | 2024-02-12 13:52:00 +0000 | [diff] [blame] | 264 | } |
Michael Merg | 86cca74 | 2024-06-11 15:24:05 +0000 | [diff] [blame] | 265 | results = append(results, result) |
Michael Merg | 6bafd75 | 2024-02-12 13:52:00 +0000 | [diff] [blame] | 266 | |
Michael Merg | 6bafd75 | 2024-02-12 13:52:00 +0000 | [diff] [blame] | 267 | var generated []*pb.GeneratedFile |
Michael Merg | 86cca74 | 2024-06-11 15:24:05 +0000 | [diff] [blame] | 268 | for _, f := range s.Generated { |
| 269 | generated = append(generated, &pb.GeneratedFile{ |
| 270 | Path: f.GetPath(), |
| 271 | Contents: f.GetContents(), |
| 272 | }) |
| 273 | } |
| 274 | genUnit := &pb.BuildableUnit{ |
| 275 | Id: "genfiles_for_" + s.GetPath(), |
| 276 | SourceFilePaths: s.GetDeps(), |
| 277 | GeneratedFiles: generated, |
| 278 | } |
Michael Merg | 6bafd75 | 2024-02-12 13:52:00 +0000 | [diff] [blame] | 279 | |
Michael Merg | 86cca74 | 2024-06-11 15:24:05 +0000 | [diff] [blame] | 280 | unit := &pb.BuildableUnit{ |
| 281 | Id: s.GetPath(), |
| 282 | Language: pb.Language_LANGUAGE_CPP, |
| 283 | SourceFilePaths: []string{s.GetPath()}, |
| 284 | CompilerArguments: s.GetCompilerArguments(), |
| 285 | DependencyIds: []string{genUnit.GetId()}, |
| 286 | } |
| 287 | units = append(units, unit, genUnit) |
| 288 | } |
| 289 | return results, units, nil |
| 290 | } |
| 291 | |
| 292 | // findJavaModules tries to find the modules that cover the given file paths. |
| 293 | // If a file is covered by multiple modules, the first module is returned. |
| 294 | func findJavaModules(paths []string, modules map[string]*javaModule) map[string]string { |
| 295 | ret := make(map[string]string) |
Ilshat Aliyev | cb4d82e | 2024-10-23 09:21:30 +0000 | [diff] [blame] | 296 | // A file may be part of multiple modules. To make the result deterministic, |
| 297 | // check the modules in sorted order. |
| 298 | keys := make([]string, 0, len(modules)) |
| 299 | for name := range modules { |
| 300 | keys = append(keys, name) |
| 301 | } |
| 302 | slices.Sort(keys) |
| 303 | for _, name := range keys { |
Michael Merg | 86cca74 | 2024-06-11 15:24:05 +0000 | [diff] [blame] | 304 | if strings.HasSuffix(name, ".impl") { |
| 305 | continue |
| 306 | } |
| 307 | |
Ilshat Aliyev | cb4d82e | 2024-10-23 09:21:30 +0000 | [diff] [blame] | 308 | module := modules[name] |
Michael Merg | 86cca74 | 2024-06-11 15:24:05 +0000 | [diff] [blame] | 309 | for i, p := range paths { |
| 310 | if slices.Contains(module.Srcs, p) { |
| 311 | ret[p] = name |
| 312 | paths = append(paths[:i], paths[i+1:]...) |
| 313 | break |
Michael Merg | 6bafd75 | 2024-02-12 13:52:00 +0000 | [diff] [blame] | 314 | } |
| 315 | } |
Michael Merg | 86cca74 | 2024-06-11 15:24:05 +0000 | [diff] [blame] | 316 | if len(paths) == 0 { |
| 317 | break |
| 318 | } |
Michael Merg | 6bafd75 | 2024-02-12 13:52:00 +0000 | [diff] [blame] | 319 | } |
Michael Merg | 86cca74 | 2024-06-11 15:24:05 +0000 | [diff] [blame] | 320 | return ret |
| 321 | } |
| 322 | |
| 323 | func getJavaInputs(env Env, modulesByPath map[string]string, modules map[string]*javaModule) ([]*pb.AnalysisResult, []*pb.BuildableUnit) { |
| 324 | var results []*pb.AnalysisResult |
| 325 | unitsById := make(map[string]*pb.BuildableUnit) |
| 326 | for p, moduleName := range modulesByPath { |
| 327 | r := &pb.AnalysisResult{ |
| 328 | SourceFilePath: p, |
| 329 | } |
| 330 | results = append(results, r) |
| 331 | |
| 332 | m := modules[moduleName] |
| 333 | if m == nil { |
| 334 | r.Status = &pb.AnalysisResult_Status{ |
| 335 | Code: pb.AnalysisResult_Status_CODE_NOT_FOUND, |
| 336 | StatusMessage: proto.String("File not found in any module."), |
| 337 | } |
| 338 | continue |
| 339 | } |
| 340 | |
| 341 | r.UnitId = moduleName |
| 342 | r.Status = &pb.AnalysisResult_Status{Code: pb.AnalysisResult_Status_CODE_OK} |
| 343 | if unitsById[r.UnitId] != nil { |
| 344 | // File is covered by an already created unit. |
| 345 | continue |
| 346 | } |
| 347 | |
| 348 | u := &pb.BuildableUnit{ |
| 349 | Id: moduleName, |
| 350 | Language: pb.Language_LANGUAGE_JAVA, |
| 351 | SourceFilePaths: m.Srcs, |
Ilshat Aliyev | 4d49111 | 2024-10-10 09:12:21 +0000 | [diff] [blame] | 352 | GeneratedFiles: genFiles(env, m), |
| 353 | DependencyIds: m.Deps, |
Michael Merg | 86cca74 | 2024-06-11 15:24:05 +0000 | [diff] [blame] | 354 | } |
| 355 | unitsById[u.Id] = u |
| 356 | |
| 357 | q := list.New() |
| 358 | for _, d := range m.Deps { |
| 359 | q.PushBack(d) |
| 360 | } |
| 361 | for q.Len() > 0 { |
| 362 | name := q.Remove(q.Front()).(string) |
| 363 | mod := modules[name] |
| 364 | if mod == nil || unitsById[name] != nil { |
| 365 | continue |
| 366 | } |
| 367 | |
Michael Merg | 86cca74 | 2024-06-11 15:24:05 +0000 | [diff] [blame] | 368 | unitsById[name] = &pb.BuildableUnit{ |
| 369 | Id: name, |
| 370 | SourceFilePaths: mod.Srcs, |
Ilshat Aliyev | 4d49111 | 2024-10-10 09:12:21 +0000 | [diff] [blame] | 371 | GeneratedFiles: genFiles(env, mod), |
Ilshat Aliyev | d297a09 | 2024-08-23 12:31:09 +0000 | [diff] [blame] | 372 | DependencyIds: mod.Deps, |
Michael Merg | 86cca74 | 2024-06-11 15:24:05 +0000 | [diff] [blame] | 373 | } |
| 374 | |
| 375 | for _, d := range mod.Deps { |
| 376 | q.PushBack(d) |
| 377 | } |
| 378 | } |
Michael Merg | 6bafd75 | 2024-02-12 13:52:00 +0000 | [diff] [blame] | 379 | } |
Michael Merg | 86cca74 | 2024-06-11 15:24:05 +0000 | [diff] [blame] | 380 | |
| 381 | units := make([]*pb.BuildableUnit, 0, len(unitsById)) |
| 382 | for _, u := range unitsById { |
| 383 | units = append(units, u) |
| 384 | } |
| 385 | return results, units |
| 386 | } |
| 387 | |
| 388 | // genFiles returns the generated files (paths that start with outDir/) for the |
Ilshat Aliyev | 4d49111 | 2024-10-10 09:12:21 +0000 | [diff] [blame] | 389 | // given module. Generated files that do not exist are ignored. |
| 390 | func genFiles(env Env, mod *javaModule) []*pb.GeneratedFile { |
| 391 | var paths []string |
| 392 | paths = append(paths, mod.Srcs...) |
| 393 | paths = append(paths, mod.SrcJars...) |
| 394 | paths = append(paths, mod.Jars...) |
| 395 | |
Michael Merg | 86cca74 | 2024-06-11 15:24:05 +0000 | [diff] [blame] | 396 | prefix := env.OutDir + "/" |
| 397 | var ret []*pb.GeneratedFile |
| 398 | for _, p := range paths { |
| 399 | relPath, ok := strings.CutPrefix(p, prefix) |
| 400 | if !ok { |
| 401 | continue |
| 402 | } |
| 403 | |
| 404 | contents, err := os.ReadFile(path.Join(env.RepoDir, p)) |
| 405 | if err != nil { |
| 406 | continue |
| 407 | } |
| 408 | |
| 409 | ret = append(ret, &pb.GeneratedFile{ |
| 410 | Path: relPath, |
| 411 | Contents: contents, |
| 412 | }) |
| 413 | } |
| 414 | return ret |
Michael Merg | 6bafd75 | 2024-02-12 13:52:00 +0000 | [diff] [blame] | 415 | } |
| 416 | |
| 417 | // runMake runs Soong build for the given modules. |
| 418 | func runMake(ctx context.Context, env Env, modules ...string) error { |
| 419 | args := []string{ |
| 420 | "--make-mode", |
| 421 | "ANDROID_BUILD_ENVIRONMENT_CONFIG=googler-cog", |
Michael Merg | 75d934f | 2024-04-18 12:06:31 +0000 | [diff] [blame] | 422 | "SOONG_GEN_COMPDB=1", |
Michael Merg | 6bafd75 | 2024-02-12 13:52:00 +0000 | [diff] [blame] | 423 | "TARGET_PRODUCT=" + env.LunchTarget.Product, |
| 424 | "TARGET_RELEASE=" + env.LunchTarget.Release, |
| 425 | "TARGET_BUILD_VARIANT=" + env.LunchTarget.Variant, |
Michael Merg | 86cca74 | 2024-06-11 15:24:05 +0000 | [diff] [blame] | 426 | "TARGET_BUILD_TYPE=release", |
Kadir Çetinkaya | 874e12b | 2024-03-15 07:27:30 +0000 | [diff] [blame] | 427 | "-k", |
Michael Merg | 6bafd75 | 2024-02-12 13:52:00 +0000 | [diff] [blame] | 428 | } |
| 429 | args = append(args, modules...) |
| 430 | cmd := exec.CommandContext(ctx, "build/soong/soong_ui.bash", args...) |
| 431 | cmd.Dir = env.RepoDir |
Michael Merg | d8880ab | 2024-03-20 11:05:23 +0000 | [diff] [blame] | 432 | cmd.Stdout = os.Stderr |
Michael Merg | 6bafd75 | 2024-02-12 13:52:00 +0000 | [diff] [blame] | 433 | cmd.Stderr = os.Stderr |
| 434 | return cmd.Run() |
| 435 | } |
| 436 | |
| 437 | type javaModule struct { |
Michael Merg | 6bafd75 | 2024-02-12 13:52:00 +0000 | [diff] [blame] | 438 | Path []string `json:"path,omitempty"` |
| 439 | Deps []string `json:"dependencies,omitempty"` |
| 440 | Srcs []string `json:"srcs,omitempty"` |
| 441 | Jars []string `json:"jars,omitempty"` |
| 442 | SrcJars []string `json:"srcjars,omitempty"` |
| 443 | } |
| 444 | |
Michael Merg | 86cca74 | 2024-06-11 15:24:05 +0000 | [diff] [blame] | 445 | func loadJavaModules(env Env) (map[string]*javaModule, error) { |
Kadir Çetinkaya | 0769200 | 2024-02-28 07:10:05 +0000 | [diff] [blame] | 446 | javaDepsPath := path.Join(env.RepoDir, env.OutDir, "soong/module_bp_java_deps.json") |
| 447 | data, err := os.ReadFile(javaDepsPath) |
Michael Merg | 6bafd75 | 2024-02-12 13:52:00 +0000 | [diff] [blame] | 448 | if err != nil { |
Michael Merg | 86cca74 | 2024-06-11 15:24:05 +0000 | [diff] [blame] | 449 | return nil, err |
Michael Merg | 6bafd75 | 2024-02-12 13:52:00 +0000 | [diff] [blame] | 450 | } |
| 451 | |
Michael Merg | 86cca74 | 2024-06-11 15:24:05 +0000 | [diff] [blame] | 452 | var ret map[string]*javaModule // module name -> module |
| 453 | if err = json.Unmarshal(data, &ret); err != nil { |
| 454 | return nil, err |
Michael Merg | 6bafd75 | 2024-02-12 13:52:00 +0000 | [diff] [blame] | 455 | } |
| 456 | |
Michael Merg | 86cca74 | 2024-06-11 15:24:05 +0000 | [diff] [blame] | 457 | // Add top level java_sdk_library for .impl modules. |
| 458 | for name, module := range ret { |
| 459 | if striped := strings.TrimSuffix(name, ".impl"); striped != name { |
| 460 | ret[striped] = module |
Kadir Çetinkaya | 0769200 | 2024-02-28 07:10:05 +0000 | [diff] [blame] | 461 | } |
Michael Merg | 6bafd75 | 2024-02-12 13:52:00 +0000 | [diff] [blame] | 462 | } |
Michael Merg | 86cca74 | 2024-06-11 15:24:05 +0000 | [diff] [blame] | 463 | return ret, nil |
Michael Merg | 6bafd75 | 2024-02-12 13:52:00 +0000 | [diff] [blame] | 464 | } |