1*333d2b36SAndroid Build Coastguard Worker// Copyright 2019 Google Inc. All rights reserved. 2*333d2b36SAndroid Build Coastguard Worker// 3*333d2b36SAndroid Build Coastguard Worker// Licensed under the Apache License, Version 2.0 (the "License"); 4*333d2b36SAndroid Build Coastguard Worker// you may not use this file except in compliance with the License. 5*333d2b36SAndroid Build Coastguard Worker// You may obtain a copy of the License at 6*333d2b36SAndroid Build Coastguard Worker// 7*333d2b36SAndroid Build Coastguard Worker// http://www.apache.org/licenses/LICENSE-2.0 8*333d2b36SAndroid Build Coastguard Worker// 9*333d2b36SAndroid Build Coastguard Worker// Unless required by applicable law or agreed to in writing, software 10*333d2b36SAndroid Build Coastguard Worker// distributed under the License is distributed on an "AS IS" BASIS, 11*333d2b36SAndroid Build Coastguard Worker// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12*333d2b36SAndroid Build Coastguard Worker// See the License for the specific language governing permissions and 13*333d2b36SAndroid Build Coastguard Worker// limitations under the License. 14*333d2b36SAndroid Build Coastguard Worker 15*333d2b36SAndroid Build Coastguard Workerpackage cc 16*333d2b36SAndroid Build Coastguard Worker 17*333d2b36SAndroid Build Coastguard Workerimport ( 18*333d2b36SAndroid Build Coastguard Worker "encoding/json" 19*333d2b36SAndroid Build Coastguard Worker "fmt" 20*333d2b36SAndroid Build Coastguard Worker "path" 21*333d2b36SAndroid Build Coastguard Worker "sort" 22*333d2b36SAndroid Build Coastguard Worker "strings" 23*333d2b36SAndroid Build Coastguard Worker 24*333d2b36SAndroid Build Coastguard Worker "android/soong/android" 25*333d2b36SAndroid Build Coastguard Worker) 26*333d2b36SAndroid Build Coastguard Worker 27*333d2b36SAndroid Build Coastguard Worker// This singleton collects cc modules' source and flags into to a json file. 28*333d2b36SAndroid Build Coastguard Worker// It does so for generating CMakeLists.txt project files needed data when 29*333d2b36SAndroid Build Coastguard Worker// either make, mm, mma, mmm or mmma is called. 30*333d2b36SAndroid Build Coastguard Worker// The info file is generated in $OUT/module_bp_cc_depend.json. 31*333d2b36SAndroid Build Coastguard Worker 32*333d2b36SAndroid Build Coastguard Workerfunc init() { 33*333d2b36SAndroid Build Coastguard Worker android.RegisterParallelSingletonType("ccdeps_generator", ccDepsGeneratorSingleton) 34*333d2b36SAndroid Build Coastguard Worker} 35*333d2b36SAndroid Build Coastguard Worker 36*333d2b36SAndroid Build Coastguard Workerfunc ccDepsGeneratorSingleton() android.Singleton { 37*333d2b36SAndroid Build Coastguard Worker return &ccdepsGeneratorSingleton{} 38*333d2b36SAndroid Build Coastguard Worker} 39*333d2b36SAndroid Build Coastguard Worker 40*333d2b36SAndroid Build Coastguard Workertype ccdepsGeneratorSingleton struct { 41*333d2b36SAndroid Build Coastguard Worker outputPath android.Path 42*333d2b36SAndroid Build Coastguard Worker} 43*333d2b36SAndroid Build Coastguard Worker 44*333d2b36SAndroid Build Coastguard Workervar _ android.SingletonMakeVarsProvider = (*ccdepsGeneratorSingleton)(nil) 45*333d2b36SAndroid Build Coastguard Worker 46*333d2b36SAndroid Build Coastguard Workerconst ( 47*333d2b36SAndroid Build Coastguard Worker ccdepsJsonFileName = "module_bp_cc_deps.json" 48*333d2b36SAndroid Build Coastguard Worker cClang = "clang" 49*333d2b36SAndroid Build Coastguard Worker cppClang = "clang++" 50*333d2b36SAndroid Build Coastguard Worker) 51*333d2b36SAndroid Build Coastguard Worker 52*333d2b36SAndroid Build Coastguard Workertype ccIdeInfo struct { 53*333d2b36SAndroid Build Coastguard Worker Path []string `json:"path,omitempty"` 54*333d2b36SAndroid Build Coastguard Worker Srcs []string `json:"srcs,omitempty"` 55*333d2b36SAndroid Build Coastguard Worker Global_Common_Flags ccParameters `json:"global_common_flags,omitempty"` 56*333d2b36SAndroid Build Coastguard Worker Local_Common_Flags ccParameters `json:"local_common_flags,omitempty"` 57*333d2b36SAndroid Build Coastguard Worker Global_C_flags ccParameters `json:"global_c_flags,omitempty"` 58*333d2b36SAndroid Build Coastguard Worker Local_C_flags ccParameters `json:"local_c_flags,omitempty"` 59*333d2b36SAndroid Build Coastguard Worker Global_C_only_flags ccParameters `json:"global_c_only_flags,omitempty"` 60*333d2b36SAndroid Build Coastguard Worker Local_C_only_flags ccParameters `json:"local_c_only_flags,omitempty"` 61*333d2b36SAndroid Build Coastguard Worker Global_Cpp_flags ccParameters `json:"global_cpp_flags,omitempty"` 62*333d2b36SAndroid Build Coastguard Worker Local_Cpp_flags ccParameters `json:"local_cpp_flags,omitempty"` 63*333d2b36SAndroid Build Coastguard Worker System_include_flags ccParameters `json:"system_include_flags,omitempty"` 64*333d2b36SAndroid Build Coastguard Worker Module_name string `json:"module_name,omitempty"` 65*333d2b36SAndroid Build Coastguard Worker} 66*333d2b36SAndroid Build Coastguard Worker 67*333d2b36SAndroid Build Coastguard Workertype ccParameters struct { 68*333d2b36SAndroid Build Coastguard Worker HeaderSearchPath []string `json:"header_search_path,omitempty"` 69*333d2b36SAndroid Build Coastguard Worker SystemHeaderSearchPath []string `json:"system_search_path,omitempty"` 70*333d2b36SAndroid Build Coastguard Worker FlagParameters []string `json:"flag,omitempty"` 71*333d2b36SAndroid Build Coastguard Worker SysRoot string `json:"system_root,omitempty"` 72*333d2b36SAndroid Build Coastguard Worker RelativeFilePathFlags map[string]string `json:"relative_file_path,omitempty"` 73*333d2b36SAndroid Build Coastguard Worker} 74*333d2b36SAndroid Build Coastguard Worker 75*333d2b36SAndroid Build Coastguard Workertype ccMapIdeInfos map[string]ccIdeInfo 76*333d2b36SAndroid Build Coastguard Worker 77*333d2b36SAndroid Build Coastguard Workertype ccDeps struct { 78*333d2b36SAndroid Build Coastguard Worker C_clang string `json:"clang,omitempty"` 79*333d2b36SAndroid Build Coastguard Worker Cpp_clang string `json:"clang++,omitempty"` 80*333d2b36SAndroid Build Coastguard Worker Modules ccMapIdeInfos `json:"modules,omitempty"` 81*333d2b36SAndroid Build Coastguard Worker} 82*333d2b36SAndroid Build Coastguard Worker 83*333d2b36SAndroid Build Coastguard Workerfunc (c *ccdepsGeneratorSingleton) GenerateBuildActions(ctx android.SingletonContext) { 84*333d2b36SAndroid Build Coastguard Worker // (b/204397180) Generate module_bp_cc_deps.json by default. 85*333d2b36SAndroid Build Coastguard Worker moduleDeps := ccDeps{} 86*333d2b36SAndroid Build Coastguard Worker moduleInfos := map[string]ccIdeInfo{} 87*333d2b36SAndroid Build Coastguard Worker 88*333d2b36SAndroid Build Coastguard Worker // Track if best variant (device arch match) has been found. 89*333d2b36SAndroid Build Coastguard Worker bestVariantFound := map[string]bool{} 90*333d2b36SAndroid Build Coastguard Worker 91*333d2b36SAndroid Build Coastguard Worker pathToCC, _ := evalVariable(ctx, "${config.ClangBin}/") 92*333d2b36SAndroid Build Coastguard Worker moduleDeps.C_clang = fmt.Sprintf("%s%s", buildCMakePath(pathToCC), cClang) 93*333d2b36SAndroid Build Coastguard Worker moduleDeps.Cpp_clang = fmt.Sprintf("%s%s", buildCMakePath(pathToCC), cppClang) 94*333d2b36SAndroid Build Coastguard Worker 95*333d2b36SAndroid Build Coastguard Worker ctx.VisitAllModules(func(module android.Module) { 96*333d2b36SAndroid Build Coastguard Worker if ccModule, ok := module.(*Module); ok { 97*333d2b36SAndroid Build Coastguard Worker if compiledModule, ok := ccModule.compiler.(CompiledInterface); ok { 98*333d2b36SAndroid Build Coastguard Worker generateCLionProjectData(ctx, compiledModule, ccModule, bestVariantFound, moduleInfos) 99*333d2b36SAndroid Build Coastguard Worker } 100*333d2b36SAndroid Build Coastguard Worker } 101*333d2b36SAndroid Build Coastguard Worker }) 102*333d2b36SAndroid Build Coastguard Worker 103*333d2b36SAndroid Build Coastguard Worker moduleDeps.Modules = moduleInfos 104*333d2b36SAndroid Build Coastguard Worker 105*333d2b36SAndroid Build Coastguard Worker ccfpath := android.PathForOutput(ctx, ccdepsJsonFileName) 106*333d2b36SAndroid Build Coastguard Worker err := createJsonFile(moduleDeps, ccfpath) 107*333d2b36SAndroid Build Coastguard Worker if err != nil { 108*333d2b36SAndroid Build Coastguard Worker ctx.Errorf(err.Error()) 109*333d2b36SAndroid Build Coastguard Worker } 110*333d2b36SAndroid Build Coastguard Worker c.outputPath = ccfpath 111*333d2b36SAndroid Build Coastguard Worker 112*333d2b36SAndroid Build Coastguard Worker // This is necessary to satisfy the dangling rules check as this file is written by Soong rather than a rule. 113*333d2b36SAndroid Build Coastguard Worker ctx.Build(pctx, android.BuildParams{ 114*333d2b36SAndroid Build Coastguard Worker Rule: android.Touch, 115*333d2b36SAndroid Build Coastguard Worker Output: ccfpath, 116*333d2b36SAndroid Build Coastguard Worker }) 117*333d2b36SAndroid Build Coastguard Worker} 118*333d2b36SAndroid Build Coastguard Worker 119*333d2b36SAndroid Build Coastguard Workerfunc (c *ccdepsGeneratorSingleton) MakeVars(ctx android.MakeVarsContext) { 120*333d2b36SAndroid Build Coastguard Worker if c.outputPath == nil { 121*333d2b36SAndroid Build Coastguard Worker return 122*333d2b36SAndroid Build Coastguard Worker } 123*333d2b36SAndroid Build Coastguard Worker 124*333d2b36SAndroid Build Coastguard Worker ctx.DistForGoal("general-tests", c.outputPath) 125*333d2b36SAndroid Build Coastguard Worker} 126*333d2b36SAndroid Build Coastguard Worker 127*333d2b36SAndroid Build Coastguard Workerfunc parseCompilerCCParameters(ctx android.SingletonContext, params []string) ccParameters { 128*333d2b36SAndroid Build Coastguard Worker compilerParams := ccParameters{} 129*333d2b36SAndroid Build Coastguard Worker 130*333d2b36SAndroid Build Coastguard Worker cparams := []string{} 131*333d2b36SAndroid Build Coastguard Worker for _, param := range params { 132*333d2b36SAndroid Build Coastguard Worker param, _ = evalVariable(ctx, param) 133*333d2b36SAndroid Build Coastguard Worker cparams = append(cparams, param) 134*333d2b36SAndroid Build Coastguard Worker } 135*333d2b36SAndroid Build Coastguard Worker 136*333d2b36SAndroid Build Coastguard Worker // Soong does not guarantee that each flag will be in an individual string. e.g: The 137*333d2b36SAndroid Build Coastguard Worker // input received could be: 138*333d2b36SAndroid Build Coastguard Worker // params = {"-isystem", "path/to/system"} 139*333d2b36SAndroid Build Coastguard Worker // or it could be 140*333d2b36SAndroid Build Coastguard Worker // params = {"-isystem path/to/system"} 141*333d2b36SAndroid Build Coastguard Worker // To normalize the input, we split all strings with the "space" character and consolidate 142*333d2b36SAndroid Build Coastguard Worker // all tokens into a flattened parameters list 143*333d2b36SAndroid Build Coastguard Worker cparams = normalizeParameters(cparams) 144*333d2b36SAndroid Build Coastguard Worker 145*333d2b36SAndroid Build Coastguard Worker for i := 0; i < len(cparams); i++ { 146*333d2b36SAndroid Build Coastguard Worker param := cparams[i] 147*333d2b36SAndroid Build Coastguard Worker if param == "" { 148*333d2b36SAndroid Build Coastguard Worker continue 149*333d2b36SAndroid Build Coastguard Worker } 150*333d2b36SAndroid Build Coastguard Worker 151*333d2b36SAndroid Build Coastguard Worker switch categorizeParameter(param) { 152*333d2b36SAndroid Build Coastguard Worker case headerSearchPath: 153*333d2b36SAndroid Build Coastguard Worker compilerParams.HeaderSearchPath = 154*333d2b36SAndroid Build Coastguard Worker append(compilerParams.HeaderSearchPath, strings.TrimPrefix(param, "-I")) 155*333d2b36SAndroid Build Coastguard Worker case systemHeaderSearchPath: 156*333d2b36SAndroid Build Coastguard Worker if i < len(cparams)-1 { 157*333d2b36SAndroid Build Coastguard Worker compilerParams.SystemHeaderSearchPath = append(compilerParams.SystemHeaderSearchPath, cparams[i+1]) 158*333d2b36SAndroid Build Coastguard Worker } 159*333d2b36SAndroid Build Coastguard Worker i = i + 1 160*333d2b36SAndroid Build Coastguard Worker case flag: 161*333d2b36SAndroid Build Coastguard Worker c := cleanupParameter(param) 162*333d2b36SAndroid Build Coastguard Worker compilerParams.FlagParameters = append(compilerParams.FlagParameters, c) 163*333d2b36SAndroid Build Coastguard Worker case systemRoot: 164*333d2b36SAndroid Build Coastguard Worker if i < len(cparams)-1 { 165*333d2b36SAndroid Build Coastguard Worker compilerParams.SysRoot = cparams[i+1] 166*333d2b36SAndroid Build Coastguard Worker } 167*333d2b36SAndroid Build Coastguard Worker i = i + 1 168*333d2b36SAndroid Build Coastguard Worker case relativeFilePathFlag: 169*333d2b36SAndroid Build Coastguard Worker flagComponents := strings.Split(param, "=") 170*333d2b36SAndroid Build Coastguard Worker if len(flagComponents) == 2 { 171*333d2b36SAndroid Build Coastguard Worker if compilerParams.RelativeFilePathFlags == nil { 172*333d2b36SAndroid Build Coastguard Worker compilerParams.RelativeFilePathFlags = map[string]string{} 173*333d2b36SAndroid Build Coastguard Worker } 174*333d2b36SAndroid Build Coastguard Worker compilerParams.RelativeFilePathFlags[flagComponents[0]] = flagComponents[1] 175*333d2b36SAndroid Build Coastguard Worker } 176*333d2b36SAndroid Build Coastguard Worker } 177*333d2b36SAndroid Build Coastguard Worker } 178*333d2b36SAndroid Build Coastguard Worker return compilerParams 179*333d2b36SAndroid Build Coastguard Worker} 180*333d2b36SAndroid Build Coastguard Worker 181*333d2b36SAndroid Build Coastguard Workerfunc generateCLionProjectData(ctx android.SingletonContext, compiledModule CompiledInterface, 182*333d2b36SAndroid Build Coastguard Worker ccModule *Module, bestVariantFound map[string]bool, moduleInfos map[string]ccIdeInfo) { 183*333d2b36SAndroid Build Coastguard Worker moduleName := ccModule.ModuleBase.Name() 184*333d2b36SAndroid Build Coastguard Worker srcs := compiledModule.Srcs() 185*333d2b36SAndroid Build Coastguard Worker 186*333d2b36SAndroid Build Coastguard Worker // Skip if best variant has already been found. 187*333d2b36SAndroid Build Coastguard Worker if bestVariantFound[moduleName] { 188*333d2b36SAndroid Build Coastguard Worker return 189*333d2b36SAndroid Build Coastguard Worker } 190*333d2b36SAndroid Build Coastguard Worker 191*333d2b36SAndroid Build Coastguard Worker // Skip if sources are empty. 192*333d2b36SAndroid Build Coastguard Worker if len(srcs) == 0 { 193*333d2b36SAndroid Build Coastguard Worker return 194*333d2b36SAndroid Build Coastguard Worker } 195*333d2b36SAndroid Build Coastguard Worker 196*333d2b36SAndroid Build Coastguard Worker // Check if device arch matches, in which case this is the best variant and takes precedence. 197*333d2b36SAndroid Build Coastguard Worker if ccModule.Device() && ccModule.ModuleBase.Arch().ArchType.Name == ctx.DeviceConfig().DeviceArch() { 198*333d2b36SAndroid Build Coastguard Worker bestVariantFound[moduleName] = true 199*333d2b36SAndroid Build Coastguard Worker } else if _, ok := moduleInfos[moduleName]; ok { 200*333d2b36SAndroid Build Coastguard Worker // Skip because this isn't the best variant and a previous one has already been added. 201*333d2b36SAndroid Build Coastguard Worker // Heuristically, ones that appear first are likely to be more relevant. 202*333d2b36SAndroid Build Coastguard Worker return 203*333d2b36SAndroid Build Coastguard Worker } 204*333d2b36SAndroid Build Coastguard Worker 205*333d2b36SAndroid Build Coastguard Worker dpInfo := ccIdeInfo{} 206*333d2b36SAndroid Build Coastguard Worker 207*333d2b36SAndroid Build Coastguard Worker dpInfo.Path = append(dpInfo.Path, path.Dir(ctx.BlueprintFile(ccModule))) 208*333d2b36SAndroid Build Coastguard Worker dpInfo.Srcs = append(dpInfo.Srcs, srcs.Strings()...) 209*333d2b36SAndroid Build Coastguard Worker dpInfo.Path = android.FirstUniqueStrings(dpInfo.Path) 210*333d2b36SAndroid Build Coastguard Worker dpInfo.Srcs = android.FirstUniqueStrings(dpInfo.Srcs) 211*333d2b36SAndroid Build Coastguard Worker 212*333d2b36SAndroid Build Coastguard Worker dpInfo.Global_Common_Flags = parseCompilerCCParameters(ctx, ccModule.flags.Global.CommonFlags) 213*333d2b36SAndroid Build Coastguard Worker dpInfo.Local_Common_Flags = parseCompilerCCParameters(ctx, ccModule.flags.Local.CommonFlags) 214*333d2b36SAndroid Build Coastguard Worker dpInfo.Global_C_flags = parseCompilerCCParameters(ctx, ccModule.flags.Global.CFlags) 215*333d2b36SAndroid Build Coastguard Worker dpInfo.Local_C_flags = parseCompilerCCParameters(ctx, ccModule.flags.Local.CFlags) 216*333d2b36SAndroid Build Coastguard Worker dpInfo.Global_C_only_flags = parseCompilerCCParameters(ctx, ccModule.flags.Global.ConlyFlags) 217*333d2b36SAndroid Build Coastguard Worker dpInfo.Local_C_only_flags = parseCompilerCCParameters(ctx, ccModule.flags.Local.ConlyFlags) 218*333d2b36SAndroid Build Coastguard Worker dpInfo.Global_Cpp_flags = parseCompilerCCParameters(ctx, ccModule.flags.Global.CppFlags) 219*333d2b36SAndroid Build Coastguard Worker dpInfo.Local_Cpp_flags = parseCompilerCCParameters(ctx, ccModule.flags.Local.CppFlags) 220*333d2b36SAndroid Build Coastguard Worker dpInfo.System_include_flags = parseCompilerCCParameters(ctx, ccModule.flags.SystemIncludeFlags) 221*333d2b36SAndroid Build Coastguard Worker 222*333d2b36SAndroid Build Coastguard Worker dpInfo.Module_name = moduleName 223*333d2b36SAndroid Build Coastguard Worker 224*333d2b36SAndroid Build Coastguard Worker moduleInfos[moduleName] = dpInfo 225*333d2b36SAndroid Build Coastguard Worker} 226*333d2b36SAndroid Build Coastguard Worker 227*333d2b36SAndroid Build Coastguard Workertype Deal struct { 228*333d2b36SAndroid Build Coastguard Worker Name string 229*333d2b36SAndroid Build Coastguard Worker ideInfo ccIdeInfo 230*333d2b36SAndroid Build Coastguard Worker} 231*333d2b36SAndroid Build Coastguard Worker 232*333d2b36SAndroid Build Coastguard Workertype Deals []Deal 233*333d2b36SAndroid Build Coastguard Worker 234*333d2b36SAndroid Build Coastguard Worker// Ensure it satisfies sort.Interface 235*333d2b36SAndroid Build Coastguard Workerfunc (d Deals) Len() int { return len(d) } 236*333d2b36SAndroid Build Coastguard Workerfunc (d Deals) Less(i, j int) bool { return d[i].Name < d[j].Name } 237*333d2b36SAndroid Build Coastguard Workerfunc (d Deals) Swap(i, j int) { d[i], d[j] = d[j], d[i] } 238*333d2b36SAndroid Build Coastguard Worker 239*333d2b36SAndroid Build Coastguard Workerfunc sortMap(moduleInfos map[string]ccIdeInfo) map[string]ccIdeInfo { 240*333d2b36SAndroid Build Coastguard Worker var deals Deals 241*333d2b36SAndroid Build Coastguard Worker for k, v := range moduleInfos { 242*333d2b36SAndroid Build Coastguard Worker deals = append(deals, Deal{k, v}) 243*333d2b36SAndroid Build Coastguard Worker } 244*333d2b36SAndroid Build Coastguard Worker 245*333d2b36SAndroid Build Coastguard Worker sort.Sort(deals) 246*333d2b36SAndroid Build Coastguard Worker 247*333d2b36SAndroid Build Coastguard Worker m := map[string]ccIdeInfo{} 248*333d2b36SAndroid Build Coastguard Worker for _, d := range deals { 249*333d2b36SAndroid Build Coastguard Worker m[d.Name] = d.ideInfo 250*333d2b36SAndroid Build Coastguard Worker } 251*333d2b36SAndroid Build Coastguard Worker return m 252*333d2b36SAndroid Build Coastguard Worker} 253*333d2b36SAndroid Build Coastguard Worker 254*333d2b36SAndroid Build Coastguard Workerfunc createJsonFile(moduleDeps ccDeps, ccfpath android.WritablePath) error { 255*333d2b36SAndroid Build Coastguard Worker buf, err := json.MarshalIndent(moduleDeps, "", "\t") 256*333d2b36SAndroid Build Coastguard Worker if err != nil { 257*333d2b36SAndroid Build Coastguard Worker return fmt.Errorf("JSON marshal of cc deps failed: %s", err) 258*333d2b36SAndroid Build Coastguard Worker } 259*333d2b36SAndroid Build Coastguard Worker err = android.WriteFileToOutputDir(ccfpath, buf, 0666) 260*333d2b36SAndroid Build Coastguard Worker if err != nil { 261*333d2b36SAndroid Build Coastguard Worker return fmt.Errorf("Writing cc deps to %s failed: %s", ccfpath.String(), err) 262*333d2b36SAndroid Build Coastguard Worker } 263*333d2b36SAndroid Build Coastguard Worker return nil 264*333d2b36SAndroid Build Coastguard Worker} 265