blob: 4247778e8e5d2bdc3cf603ac0e5605f99447a03e [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
44const (
Jim Tangc44ba2a2021-11-03 15:55:01 +080045 ccdepsJsonFileName = "module_bp_cc_deps.json"
46 cClang = "clang"
47 cppClang = "clang++"
bralee5a5cce62019-10-22 13:39:18 +080048)
49
50type ccIdeInfo struct {
51 Path []string `json:"path,omitempty"`
52 Srcs []string `json:"srcs,omitempty"`
53 Global_Common_Flags ccParameters `json:"global_common_flags,omitempty"`
54 Local_Common_Flags ccParameters `json:"local_common_flags,omitempty"`
55 Global_C_flags ccParameters `json:"global_c_flags,omitempty"`
56 Local_C_flags ccParameters `json:"local_c_flags,omitempty"`
57 Global_C_only_flags ccParameters `json:"global_c_only_flags,omitempty"`
58 Local_C_only_flags ccParameters `json:"local_c_only_flags,omitempty"`
59 Global_Cpp_flags ccParameters `json:"global_cpp_flags,omitempty"`
60 Local_Cpp_flags ccParameters `json:"local_cpp_flags,omitempty"`
61 System_include_flags ccParameters `json:"system_include_flags,omitempty"`
62 Module_name string `json:"module_name,omitempty"`
63}
64
65type ccParameters struct {
66 HeaderSearchPath []string `json:"header_search_path,omitempty"`
67 SystemHeaderSearchPath []string `json:"system_search_path,omitempty"`
68 FlagParameters []string `json:"flag,omitempty"`
69 SysRoot string `json:"system_root,omitempty"`
70 RelativeFilePathFlags map[string]string `json:"relative_file_path,omitempty"`
71}
72
73type ccMapIdeInfos map[string]ccIdeInfo
74
75type ccDeps struct {
76 C_clang string `json:"clang,omitempty"`
77 Cpp_clang string `json:"clang++,omitempty"`
78 Modules ccMapIdeInfos `json:"modules,omitempty"`
79}
80
81func (c *ccdepsGeneratorSingleton) GenerateBuildActions(ctx android.SingletonContext) {
Jim Tangc44ba2a2021-11-03 15:55:01 +080082 // (b/204397180) Generate module_bp_cc_deps.json by default.
bralee5a5cce62019-10-22 13:39:18 +080083 moduleDeps := ccDeps{}
84 moduleInfos := map[string]ccIdeInfo{}
85
Sean Huae783ed52024-07-16 20:15:35 +000086 // Track if best variant (device arch match) has been found.
87 bestVariantFound := map[string]bool{}
bralee5a5cce62019-10-22 13:39:18 +080088
89 pathToCC, _ := evalVariable(ctx, "${config.ClangBin}/")
90 moduleDeps.C_clang = fmt.Sprintf("%s%s", buildCMakePath(pathToCC), cClang)
91 moduleDeps.Cpp_clang = fmt.Sprintf("%s%s", buildCMakePath(pathToCC), cppClang)
92
93 ctx.VisitAllModules(func(module android.Module) {
94 if ccModule, ok := module.(*Module); ok {
95 if compiledModule, ok := ccModule.compiler.(CompiledInterface); ok {
Sean Huae783ed52024-07-16 20:15:35 +000096 generateCLionProjectData(ctx, compiledModule, ccModule, bestVariantFound, moduleInfos)
bralee5a5cce62019-10-22 13:39:18 +080097 }
98 }
99 })
100
101 moduleDeps.Modules = moduleInfos
102
Colin Cross37c5cda2020-01-31 10:07:25 -0800103 ccfpath := android.PathForOutput(ctx, ccdepsJsonFileName)
bralee5a5cce62019-10-22 13:39:18 +0800104 err := createJsonFile(moduleDeps, ccfpath)
105 if err != nil {
106 ctx.Errorf(err.Error())
107 }
Liz Kammer5e07d0c2020-06-30 14:37:22 -0700108 c.outputPath = ccfpath
109
110 // This is necessary to satisfy the dangling rules check as this file is written by Soong rather than a rule.
111 ctx.Build(pctx, android.BuildParams{
112 Rule: android.Touch,
113 Output: ccfpath,
114 })
Liz Kammer5e07d0c2020-06-30 14:37:22 -0700115 ctx.DistForGoal("general-tests", c.outputPath)
bralee5a5cce62019-10-22 13:39:18 +0800116}
117
118func parseCompilerCCParameters(ctx android.SingletonContext, params []string) ccParameters {
119 compilerParams := ccParameters{}
120
121 cparams := []string{}
122 for _, param := range params {
123 param, _ = evalVariable(ctx, param)
124 cparams = append(cparams, param)
125 }
126
127 // Soong does not guarantee that each flag will be in an individual string. e.g: The
128 // input received could be:
129 // params = {"-isystem", "path/to/system"}
130 // or it could be
131 // params = {"-isystem path/to/system"}
132 // To normalize the input, we split all strings with the "space" character and consolidate
133 // all tokens into a flattened parameters list
134 cparams = normalizeParameters(cparams)
135
136 for i := 0; i < len(cparams); i++ {
137 param := cparams[i]
138 if param == "" {
139 continue
140 }
141
142 switch categorizeParameter(param) {
143 case headerSearchPath:
144 compilerParams.HeaderSearchPath =
145 append(compilerParams.HeaderSearchPath, strings.TrimPrefix(param, "-I"))
146 case systemHeaderSearchPath:
braleeadba3c02020-01-08 09:10:53 +0800147 if i < len(cparams)-1 {
bralee5a5cce62019-10-22 13:39:18 +0800148 compilerParams.SystemHeaderSearchPath = append(compilerParams.SystemHeaderSearchPath, cparams[i+1])
149 }
150 i = i + 1
151 case flag:
152 c := cleanupParameter(param)
153 compilerParams.FlagParameters = append(compilerParams.FlagParameters, c)
154 case systemRoot:
155 if i < len(cparams)-1 {
156 compilerParams.SysRoot = cparams[i+1]
157 }
158 i = i + 1
159 case relativeFilePathFlag:
160 flagComponents := strings.Split(param, "=")
161 if len(flagComponents) == 2 {
162 if compilerParams.RelativeFilePathFlags == nil {
163 compilerParams.RelativeFilePathFlags = map[string]string{}
164 }
165 compilerParams.RelativeFilePathFlags[flagComponents[0]] = flagComponents[1]
166 }
167 }
168 }
169 return compilerParams
170}
171
172func generateCLionProjectData(ctx android.SingletonContext, compiledModule CompiledInterface,
Sean Huae783ed52024-07-16 20:15:35 +0000173 ccModule *Module, bestVariantFound map[string]bool, moduleInfos map[string]ccIdeInfo) {
174 moduleName := ccModule.ModuleBase.Name()
bralee5a5cce62019-10-22 13:39:18 +0800175 srcs := compiledModule.Srcs()
Sean Huae783ed52024-07-16 20:15:35 +0000176
177 // Skip if best variant has already been found.
178 if bestVariantFound[moduleName] {
179 return
180 }
181
182 // Skip if sources are empty.
bralee5a5cce62019-10-22 13:39:18 +0800183 if len(srcs) == 0 {
184 return
185 }
186
Sean Huae783ed52024-07-16 20:15:35 +0000187 // Check if device arch matches, in which case this is the best variant and takes precedence.
188 if ccModule.Device() && ccModule.ModuleBase.Arch().ArchType.Name == ctx.DeviceConfig().DeviceArch() {
189 bestVariantFound[moduleName] = true
190 } else if _, ok := moduleInfos[moduleName]; ok {
191 // Skip because this isn't the best variant and a previous one has already been added.
192 // Heuristically, ones that appear first are likely to be more relevant.
bralee5a5cce62019-10-22 13:39:18 +0800193 return
194 }
195
Sean Huae783ed52024-07-16 20:15:35 +0000196 dpInfo := ccIdeInfo{}
bralee5a5cce62019-10-22 13:39:18 +0800197
198 dpInfo.Path = append(dpInfo.Path, path.Dir(ctx.BlueprintFile(ccModule)))
199 dpInfo.Srcs = append(dpInfo.Srcs, srcs.Strings()...)
200 dpInfo.Path = android.FirstUniqueStrings(dpInfo.Path)
201 dpInfo.Srcs = android.FirstUniqueStrings(dpInfo.Srcs)
202
203 dpInfo.Global_Common_Flags = parseCompilerCCParameters(ctx, ccModule.flags.Global.CommonFlags)
204 dpInfo.Local_Common_Flags = parseCompilerCCParameters(ctx, ccModule.flags.Local.CommonFlags)
205 dpInfo.Global_C_flags = parseCompilerCCParameters(ctx, ccModule.flags.Global.CFlags)
206 dpInfo.Local_C_flags = parseCompilerCCParameters(ctx, ccModule.flags.Local.CFlags)
207 dpInfo.Global_C_only_flags = parseCompilerCCParameters(ctx, ccModule.flags.Global.ConlyFlags)
208 dpInfo.Local_C_only_flags = parseCompilerCCParameters(ctx, ccModule.flags.Local.ConlyFlags)
209 dpInfo.Global_Cpp_flags = parseCompilerCCParameters(ctx, ccModule.flags.Global.CppFlags)
210 dpInfo.Local_Cpp_flags = parseCompilerCCParameters(ctx, ccModule.flags.Local.CppFlags)
211 dpInfo.System_include_flags = parseCompilerCCParameters(ctx, ccModule.flags.SystemIncludeFlags)
212
Sean Huae783ed52024-07-16 20:15:35 +0000213 dpInfo.Module_name = moduleName
bralee5a5cce62019-10-22 13:39:18 +0800214
Sean Huae783ed52024-07-16 20:15:35 +0000215 moduleInfos[moduleName] = dpInfo
bralee5a5cce62019-10-22 13:39:18 +0800216}
217
218type Deal struct {
219 Name string
220 ideInfo ccIdeInfo
221}
222
223type Deals []Deal
224
225// Ensure it satisfies sort.Interface
226func (d Deals) Len() int { return len(d) }
227func (d Deals) Less(i, j int) bool { return d[i].Name < d[j].Name }
228func (d Deals) Swap(i, j int) { d[i], d[j] = d[j], d[i] }
229
230func sortMap(moduleInfos map[string]ccIdeInfo) map[string]ccIdeInfo {
231 var deals Deals
232 for k, v := range moduleInfos {
233 deals = append(deals, Deal{k, v})
234 }
235
236 sort.Sort(deals)
237
238 m := map[string]ccIdeInfo{}
239 for _, d := range deals {
240 m[d.Name] = d.ideInfo
241 }
242 return m
243}
244
Colin Cross37c5cda2020-01-31 10:07:25 -0800245func createJsonFile(moduleDeps ccDeps, ccfpath android.WritablePath) error {
bralee5a5cce62019-10-22 13:39:18 +0800246 buf, err := json.MarshalIndent(moduleDeps, "", "\t")
247 if err != nil {
Colin Cross37c5cda2020-01-31 10:07:25 -0800248 return fmt.Errorf("JSON marshal of cc deps failed: %s", err)
bralee5a5cce62019-10-22 13:39:18 +0800249 }
Colin Cross37c5cda2020-01-31 10:07:25 -0800250 err = android.WriteFileToOutputDir(ccfpath, buf, 0666)
251 if err != nil {
252 return fmt.Errorf("Writing cc deps to %s failed: %s", ccfpath.String(), err)
253 }
bralee5a5cce62019-10-22 13:39:18 +0800254 return nil
255}