blob: 469fe31fa03730780c9da28c5e6197c43a67d31a [file] [log] [blame]
bralee5a5cce62019-10-22 13:39:18 +08001// Copyright 2019 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 cc
16
17import (
18 "encoding/json"
19 "fmt"
bralee5a5cce62019-10-22 13:39:18 +080020 "path"
21 "sort"
22 "strings"
23
24 "android/soong/android"
25)
26
27// This singleton collects cc modules' source and flags into to a json file.
28// It does so for generating CMakeLists.txt project files needed data when
29// either make, mm, mma, mmm or mmma is called.
30// The info file is generated in $OUT/module_bp_cc_depend.json.
31
32func init() {
LaMont Jones0c10e4d2023-05-16 00:58:37 +000033 android.RegisterParallelSingletonType("ccdeps_generator", ccDepsGeneratorSingleton)
bralee5a5cce62019-10-22 13:39:18 +080034}
35
36func ccDepsGeneratorSingleton() android.Singleton {
37 return &ccdepsGeneratorSingleton{}
38}
39
40type ccdepsGeneratorSingleton struct {
Liz Kammer5e07d0c2020-06-30 14:37:22 -070041 outputPath android.Path
bralee5a5cce62019-10-22 13:39:18 +080042}
43
Liz Kammer5e07d0c2020-06-30 14:37:22 -070044var _ android.SingletonMakeVarsProvider = (*ccdepsGeneratorSingleton)(nil)
45
bralee5a5cce62019-10-22 13:39:18 +080046const (
Jim Tangc44ba2a2021-11-03 15:55:01 +080047 ccdepsJsonFileName = "module_bp_cc_deps.json"
48 cClang = "clang"
49 cppClang = "clang++"
bralee5a5cce62019-10-22 13:39:18 +080050)
51
52type ccIdeInfo struct {
53 Path []string `json:"path,omitempty"`
54 Srcs []string `json:"srcs,omitempty"`
55 Global_Common_Flags ccParameters `json:"global_common_flags,omitempty"`
56 Local_Common_Flags ccParameters `json:"local_common_flags,omitempty"`
57 Global_C_flags ccParameters `json:"global_c_flags,omitempty"`
58 Local_C_flags ccParameters `json:"local_c_flags,omitempty"`
59 Global_C_only_flags ccParameters `json:"global_c_only_flags,omitempty"`
60 Local_C_only_flags ccParameters `json:"local_c_only_flags,omitempty"`
61 Global_Cpp_flags ccParameters `json:"global_cpp_flags,omitempty"`
62 Local_Cpp_flags ccParameters `json:"local_cpp_flags,omitempty"`
63 System_include_flags ccParameters `json:"system_include_flags,omitempty"`
64 Module_name string `json:"module_name,omitempty"`
65}
66
67type ccParameters struct {
68 HeaderSearchPath []string `json:"header_search_path,omitempty"`
69 SystemHeaderSearchPath []string `json:"system_search_path,omitempty"`
70 FlagParameters []string `json:"flag,omitempty"`
71 SysRoot string `json:"system_root,omitempty"`
72 RelativeFilePathFlags map[string]string `json:"relative_file_path,omitempty"`
73}
74
75type ccMapIdeInfos map[string]ccIdeInfo
76
77type ccDeps struct {
78 C_clang string `json:"clang,omitempty"`
79 Cpp_clang string `json:"clang++,omitempty"`
80 Modules ccMapIdeInfos `json:"modules,omitempty"`
81}
82
83func (c *ccdepsGeneratorSingleton) GenerateBuildActions(ctx android.SingletonContext) {
Jim Tangc44ba2a2021-11-03 15:55:01 +080084 // (b/204397180) Generate module_bp_cc_deps.json by default.
bralee5a5cce62019-10-22 13:39:18 +080085 moduleDeps := ccDeps{}
86 moduleInfos := map[string]ccIdeInfo{}
87
Sean Huae783ed52024-07-16 20:15:35 +000088 // Track if best variant (device arch match) has been found.
89 bestVariantFound := map[string]bool{}
bralee5a5cce62019-10-22 13:39:18 +080090
91 pathToCC, _ := evalVariable(ctx, "${config.ClangBin}/")
92 moduleDeps.C_clang = fmt.Sprintf("%s%s", buildCMakePath(pathToCC), cClang)
93 moduleDeps.Cpp_clang = fmt.Sprintf("%s%s", buildCMakePath(pathToCC), cppClang)
94
95 ctx.VisitAllModules(func(module android.Module) {
96 if ccModule, ok := module.(*Module); ok {
97 if compiledModule, ok := ccModule.compiler.(CompiledInterface); ok {
Sean Huae783ed52024-07-16 20:15:35 +000098 generateCLionProjectData(ctx, compiledModule, ccModule, bestVariantFound, moduleInfos)
bralee5a5cce62019-10-22 13:39:18 +080099 }
100 }
101 })
102
103 moduleDeps.Modules = moduleInfos
104
Colin Cross37c5cda2020-01-31 10:07:25 -0800105 ccfpath := android.PathForOutput(ctx, ccdepsJsonFileName)
bralee5a5cce62019-10-22 13:39:18 +0800106 err := createJsonFile(moduleDeps, ccfpath)
107 if err != nil {
108 ctx.Errorf(err.Error())
109 }
Liz Kammer5e07d0c2020-06-30 14:37:22 -0700110 c.outputPath = ccfpath
111
112 // This is necessary to satisfy the dangling rules check as this file is written by Soong rather than a rule.
113 ctx.Build(pctx, android.BuildParams{
114 Rule: android.Touch,
115 Output: ccfpath,
116 })
117}
118
119func (c *ccdepsGeneratorSingleton) MakeVars(ctx android.MakeVarsContext) {
120 if c.outputPath == nil {
121 return
122 }
123
124 ctx.DistForGoal("general-tests", c.outputPath)
bralee5a5cce62019-10-22 13:39:18 +0800125}
126
127func parseCompilerCCParameters(ctx android.SingletonContext, params []string) ccParameters {
128 compilerParams := ccParameters{}
129
130 cparams := []string{}
131 for _, param := range params {
132 param, _ = evalVariable(ctx, param)
133 cparams = append(cparams, param)
134 }
135
136 // Soong does not guarantee that each flag will be in an individual string. e.g: The
137 // input received could be:
138 // params = {"-isystem", "path/to/system"}
139 // or it could be
140 // params = {"-isystem path/to/system"}
141 // To normalize the input, we split all strings with the "space" character and consolidate
142 // all tokens into a flattened parameters list
143 cparams = normalizeParameters(cparams)
144
145 for i := 0; i < len(cparams); i++ {
146 param := cparams[i]
147 if param == "" {
148 continue
149 }
150
151 switch categorizeParameter(param) {
152 case headerSearchPath:
153 compilerParams.HeaderSearchPath =
154 append(compilerParams.HeaderSearchPath, strings.TrimPrefix(param, "-I"))
155 case systemHeaderSearchPath:
braleeadba3c02020-01-08 09:10:53 +0800156 if i < len(cparams)-1 {
bralee5a5cce62019-10-22 13:39:18 +0800157 compilerParams.SystemHeaderSearchPath = append(compilerParams.SystemHeaderSearchPath, cparams[i+1])
158 }
159 i = i + 1
160 case flag:
161 c := cleanupParameter(param)
162 compilerParams.FlagParameters = append(compilerParams.FlagParameters, c)
163 case systemRoot:
164 if i < len(cparams)-1 {
165 compilerParams.SysRoot = cparams[i+1]
166 }
167 i = i + 1
168 case relativeFilePathFlag:
169 flagComponents := strings.Split(param, "=")
170 if len(flagComponents) == 2 {
171 if compilerParams.RelativeFilePathFlags == nil {
172 compilerParams.RelativeFilePathFlags = map[string]string{}
173 }
174 compilerParams.RelativeFilePathFlags[flagComponents[0]] = flagComponents[1]
175 }
176 }
177 }
178 return compilerParams
179}
180
181func generateCLionProjectData(ctx android.SingletonContext, compiledModule CompiledInterface,
Sean Huae783ed52024-07-16 20:15:35 +0000182 ccModule *Module, bestVariantFound map[string]bool, moduleInfos map[string]ccIdeInfo) {
183 moduleName := ccModule.ModuleBase.Name()
bralee5a5cce62019-10-22 13:39:18 +0800184 srcs := compiledModule.Srcs()
Sean Huae783ed52024-07-16 20:15:35 +0000185
186 // Skip if best variant has already been found.
187 if bestVariantFound[moduleName] {
188 return
189 }
190
191 // Skip if sources are empty.
bralee5a5cce62019-10-22 13:39:18 +0800192 if len(srcs) == 0 {
193 return
194 }
195
Sean Huae783ed52024-07-16 20:15:35 +0000196 // Check if device arch matches, in which case this is the best variant and takes precedence.
197 if ccModule.Device() && ccModule.ModuleBase.Arch().ArchType.Name == ctx.DeviceConfig().DeviceArch() {
198 bestVariantFound[moduleName] = true
199 } else if _, ok := moduleInfos[moduleName]; ok {
200 // Skip because this isn't the best variant and a previous one has already been added.
201 // Heuristically, ones that appear first are likely to be more relevant.
bralee5a5cce62019-10-22 13:39:18 +0800202 return
203 }
204
Sean Huae783ed52024-07-16 20:15:35 +0000205 dpInfo := ccIdeInfo{}
bralee5a5cce62019-10-22 13:39:18 +0800206
207 dpInfo.Path = append(dpInfo.Path, path.Dir(ctx.BlueprintFile(ccModule)))
208 dpInfo.Srcs = append(dpInfo.Srcs, srcs.Strings()...)
209 dpInfo.Path = android.FirstUniqueStrings(dpInfo.Path)
210 dpInfo.Srcs = android.FirstUniqueStrings(dpInfo.Srcs)
211
212 dpInfo.Global_Common_Flags = parseCompilerCCParameters(ctx, ccModule.flags.Global.CommonFlags)
213 dpInfo.Local_Common_Flags = parseCompilerCCParameters(ctx, ccModule.flags.Local.CommonFlags)
214 dpInfo.Global_C_flags = parseCompilerCCParameters(ctx, ccModule.flags.Global.CFlags)
215 dpInfo.Local_C_flags = parseCompilerCCParameters(ctx, ccModule.flags.Local.CFlags)
216 dpInfo.Global_C_only_flags = parseCompilerCCParameters(ctx, ccModule.flags.Global.ConlyFlags)
217 dpInfo.Local_C_only_flags = parseCompilerCCParameters(ctx, ccModule.flags.Local.ConlyFlags)
218 dpInfo.Global_Cpp_flags = parseCompilerCCParameters(ctx, ccModule.flags.Global.CppFlags)
219 dpInfo.Local_Cpp_flags = parseCompilerCCParameters(ctx, ccModule.flags.Local.CppFlags)
220 dpInfo.System_include_flags = parseCompilerCCParameters(ctx, ccModule.flags.SystemIncludeFlags)
221
Sean Huae783ed52024-07-16 20:15:35 +0000222 dpInfo.Module_name = moduleName
bralee5a5cce62019-10-22 13:39:18 +0800223
Sean Huae783ed52024-07-16 20:15:35 +0000224 moduleInfos[moduleName] = dpInfo
bralee5a5cce62019-10-22 13:39:18 +0800225}
226
227type Deal struct {
228 Name string
229 ideInfo ccIdeInfo
230}
231
232type Deals []Deal
233
234// Ensure it satisfies sort.Interface
235func (d Deals) Len() int { return len(d) }
236func (d Deals) Less(i, j int) bool { return d[i].Name < d[j].Name }
237func (d Deals) Swap(i, j int) { d[i], d[j] = d[j], d[i] }
238
239func sortMap(moduleInfos map[string]ccIdeInfo) map[string]ccIdeInfo {
240 var deals Deals
241 for k, v := range moduleInfos {
242 deals = append(deals, Deal{k, v})
243 }
244
245 sort.Sort(deals)
246
247 m := map[string]ccIdeInfo{}
248 for _, d := range deals {
249 m[d.Name] = d.ideInfo
250 }
251 return m
252}
253
Colin Cross37c5cda2020-01-31 10:07:25 -0800254func createJsonFile(moduleDeps ccDeps, ccfpath android.WritablePath) error {
bralee5a5cce62019-10-22 13:39:18 +0800255 buf, err := json.MarshalIndent(moduleDeps, "", "\t")
256 if err != nil {
Colin Cross37c5cda2020-01-31 10:07:25 -0800257 return fmt.Errorf("JSON marshal of cc deps failed: %s", err)
bralee5a5cce62019-10-22 13:39:18 +0800258 }
Colin Cross37c5cda2020-01-31 10:07:25 -0800259 err = android.WriteFileToOutputDir(ccfpath, buf, 0666)
260 if err != nil {
261 return fmt.Errorf("Writing cc deps to %s failed: %s", ccfpath.String(), err)
262 }
bralee5a5cce62019-10-22 13:39:18 +0800263 return nil
264}