AIDEGen: collect cc_srcs and cc related flags in module_bp_cc_deps.json
Define a field CCSrcs and other cc related flags in a type ccIdeInfo struct and write them into out/soong/module_bp_cc_deps.json. AIDEGen can use these data to generate CMakeLists.txt by Python for multiple native projects in CLion IDE. Bug: 141512319 Test: 1. export SOONG_COLLECT_JAVA_DEPS=false SOONG_COLLECT_CC_DEPS=true;m nothing check 1). File out/soong/module_bp_cc_deps.json is generated. 2). In "JniInvocation_test" module: "path", "srcs", "global_common_flags", "local_common_flags", "global_c_flags", "local_c_flags", "global_c_conly_flags", "local_c_conly_flags", "global_cpp_flags", "local_cpp_flags" and "system_include_flags" have been created. Change-Id: I9292cc6373157ba68f013998a7364f84a70d5593
This commit is contained in:
parent
29d1336d11
commit
5a5cce695f
3 changed files with 253 additions and 8 deletions
|
@ -155,6 +155,7 @@ bootstrap_go_package {
|
||||||
"cc/androidmk.go",
|
"cc/androidmk.go",
|
||||||
"cc/builder.go",
|
"cc/builder.go",
|
||||||
"cc/cc.go",
|
"cc/cc.go",
|
||||||
|
"cc/ccdeps.go",
|
||||||
"cc/check.go",
|
"cc/check.go",
|
||||||
"cc/coverage.go",
|
"cc/coverage.go",
|
||||||
"cc/gen.go",
|
"cc/gen.go",
|
||||||
|
|
8
cc/cc.go
8
cc/cc.go
|
@ -2463,14 +2463,6 @@ func (c *Module) installable() bool {
|
||||||
return c.installer != nil && !c.Properties.PreventInstall && c.IsForPlatform() && c.outputFile.Valid()
|
return c.installer != nil && !c.Properties.PreventInstall && c.IsForPlatform() && c.outputFile.Valid()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Module) IDEInfo(dpInfo *android.IdeInfo) {
|
|
||||||
outputFiles, err := c.OutputFiles("")
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
dpInfo.Srcs = append(dpInfo.Srcs, outputFiles.Strings()...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Module) AndroidMkWriteAdditionalDependenciesForSourceAbiDiff(w io.Writer) {
|
func (c *Module) AndroidMkWriteAdditionalDependenciesForSourceAbiDiff(w io.Writer) {
|
||||||
if c.linker != nil {
|
if c.linker != nil {
|
||||||
if library, ok := c.linker.(*libraryDecorator); ok {
|
if library, ok := c.linker.(*libraryDecorator); ok {
|
||||||
|
|
252
cc/ccdeps.go
Normal file
252
cc/ccdeps.go
Normal file
|
@ -0,0 +1,252 @@
|
||||||
|
// Copyright 2019 Google Inc. All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package cc
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
|
"sort"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"android/soong/android"
|
||||||
|
)
|
||||||
|
|
||||||
|
// This singleton collects cc modules' source and flags into to a json file.
|
||||||
|
// It does so for generating CMakeLists.txt project files needed data when
|
||||||
|
// either make, mm, mma, mmm or mmma is called.
|
||||||
|
// The info file is generated in $OUT/module_bp_cc_depend.json.
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
android.RegisterSingletonType("ccdeps_generator", ccDepsGeneratorSingleton)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ccDepsGeneratorSingleton() android.Singleton {
|
||||||
|
return &ccdepsGeneratorSingleton{}
|
||||||
|
}
|
||||||
|
|
||||||
|
type ccdepsGeneratorSingleton struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
// Environment variables used to control the behavior of this singleton.
|
||||||
|
envVariableCollectCCDeps = "SOONG_COLLECT_CC_DEPS"
|
||||||
|
ccdepsJsonFileName = "module_bp_cc_deps.json"
|
||||||
|
cClang = "clang"
|
||||||
|
cppClang = "clang++"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ccIdeInfo struct {
|
||||||
|
Path []string `json:"path,omitempty"`
|
||||||
|
Srcs []string `json:"srcs,omitempty"`
|
||||||
|
Global_Common_Flags ccParameters `json:"global_common_flags,omitempty"`
|
||||||
|
Local_Common_Flags ccParameters `json:"local_common_flags,omitempty"`
|
||||||
|
Global_C_flags ccParameters `json:"global_c_flags,omitempty"`
|
||||||
|
Local_C_flags ccParameters `json:"local_c_flags,omitempty"`
|
||||||
|
Global_C_only_flags ccParameters `json:"global_c_only_flags,omitempty"`
|
||||||
|
Local_C_only_flags ccParameters `json:"local_c_only_flags,omitempty"`
|
||||||
|
Global_Cpp_flags ccParameters `json:"global_cpp_flags,omitempty"`
|
||||||
|
Local_Cpp_flags ccParameters `json:"local_cpp_flags,omitempty"`
|
||||||
|
System_include_flags ccParameters `json:"system_include_flags,omitempty"`
|
||||||
|
Module_name string `json:"module_name,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ccParameters struct {
|
||||||
|
HeaderSearchPath []string `json:"header_search_path,omitempty"`
|
||||||
|
SystemHeaderSearchPath []string `json:"system_search_path,omitempty"`
|
||||||
|
FlagParameters []string `json:"flag,omitempty"`
|
||||||
|
SysRoot string `json:"system_root,omitempty"`
|
||||||
|
RelativeFilePathFlags map[string]string `json:"relative_file_path,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ccMapIdeInfos map[string]ccIdeInfo
|
||||||
|
|
||||||
|
type ccDeps struct {
|
||||||
|
C_clang string `json:"clang,omitempty"`
|
||||||
|
Cpp_clang string `json:"clang++,omitempty"`
|
||||||
|
Modules ccMapIdeInfos `json:"modules,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ccdepsGeneratorSingleton) GenerateBuildActions(ctx android.SingletonContext) {
|
||||||
|
if !ctx.Config().IsEnvTrue(envVariableCollectCCDeps) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
moduleDeps := ccDeps{}
|
||||||
|
moduleInfos := map[string]ccIdeInfo{}
|
||||||
|
|
||||||
|
// Track which projects have already had CMakeLists.txt generated to keep the first
|
||||||
|
// variant for each project.
|
||||||
|
seenProjects := map[string]bool{}
|
||||||
|
|
||||||
|
pathToCC, _ := evalVariable(ctx, "${config.ClangBin}/")
|
||||||
|
moduleDeps.C_clang = fmt.Sprintf("%s%s", buildCMakePath(pathToCC), cClang)
|
||||||
|
moduleDeps.Cpp_clang = fmt.Sprintf("%s%s", buildCMakePath(pathToCC), cppClang)
|
||||||
|
|
||||||
|
ctx.VisitAllModules(func(module android.Module) {
|
||||||
|
if ccModule, ok := module.(*Module); ok {
|
||||||
|
if compiledModule, ok := ccModule.compiler.(CompiledInterface); ok {
|
||||||
|
generateCLionProjectData(ctx, compiledModule, ccModule, seenProjects, moduleInfos)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
moduleDeps.Modules = moduleInfos
|
||||||
|
|
||||||
|
ccfpath := android.PathForOutput(ctx, ccdepsJsonFileName).String()
|
||||||
|
err := createJsonFile(moduleDeps, ccfpath)
|
||||||
|
if err != nil {
|
||||||
|
ctx.Errorf(err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseCompilerCCParameters(ctx android.SingletonContext, params []string) ccParameters {
|
||||||
|
compilerParams := ccParameters{}
|
||||||
|
|
||||||
|
cparams := []string{}
|
||||||
|
for _, param := range params {
|
||||||
|
param, _ = evalVariable(ctx, param)
|
||||||
|
cparams = append(cparams, param)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Soong does not guarantee that each flag will be in an individual string. e.g: The
|
||||||
|
// input received could be:
|
||||||
|
// params = {"-isystem", "path/to/system"}
|
||||||
|
// or it could be
|
||||||
|
// params = {"-isystem path/to/system"}
|
||||||
|
// To normalize the input, we split all strings with the "space" character and consolidate
|
||||||
|
// all tokens into a flattened parameters list
|
||||||
|
cparams = normalizeParameters(cparams)
|
||||||
|
|
||||||
|
for i := 0; i < len(cparams); i++ {
|
||||||
|
param := cparams[i]
|
||||||
|
if param == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
switch categorizeParameter(param) {
|
||||||
|
case headerSearchPath:
|
||||||
|
compilerParams.HeaderSearchPath =
|
||||||
|
append(compilerParams.HeaderSearchPath, strings.TrimPrefix(param, "-I"))
|
||||||
|
case systemHeaderSearchPath:
|
||||||
|
if i < len(params)-1 {
|
||||||
|
compilerParams.SystemHeaderSearchPath = append(compilerParams.SystemHeaderSearchPath, cparams[i+1])
|
||||||
|
}
|
||||||
|
i = i + 1
|
||||||
|
case flag:
|
||||||
|
c := cleanupParameter(param)
|
||||||
|
compilerParams.FlagParameters = append(compilerParams.FlagParameters, c)
|
||||||
|
case systemRoot:
|
||||||
|
if i < len(cparams)-1 {
|
||||||
|
compilerParams.SysRoot = cparams[i+1]
|
||||||
|
}
|
||||||
|
i = i + 1
|
||||||
|
case relativeFilePathFlag:
|
||||||
|
flagComponents := strings.Split(param, "=")
|
||||||
|
if len(flagComponents) == 2 {
|
||||||
|
if compilerParams.RelativeFilePathFlags == nil {
|
||||||
|
compilerParams.RelativeFilePathFlags = map[string]string{}
|
||||||
|
}
|
||||||
|
compilerParams.RelativeFilePathFlags[flagComponents[0]] = flagComponents[1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return compilerParams
|
||||||
|
}
|
||||||
|
|
||||||
|
func generateCLionProjectData(ctx android.SingletonContext, compiledModule CompiledInterface,
|
||||||
|
ccModule *Module, seenProjects map[string]bool, moduleInfos map[string]ccIdeInfo) {
|
||||||
|
srcs := compiledModule.Srcs()
|
||||||
|
if len(srcs) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only keep the DeviceArch variant module.
|
||||||
|
if ctx.DeviceConfig().DeviceArch() != ccModule.ModuleBase.Arch().ArchType.Name {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
clionProjectLocation := getCMakeListsForModule(ccModule, ctx)
|
||||||
|
if seenProjects[clionProjectLocation] {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
seenProjects[clionProjectLocation] = true
|
||||||
|
|
||||||
|
name := ccModule.ModuleBase.Name()
|
||||||
|
dpInfo := moduleInfos[name]
|
||||||
|
|
||||||
|
dpInfo.Path = append(dpInfo.Path, path.Dir(ctx.BlueprintFile(ccModule)))
|
||||||
|
dpInfo.Srcs = append(dpInfo.Srcs, srcs.Strings()...)
|
||||||
|
dpInfo.Path = android.FirstUniqueStrings(dpInfo.Path)
|
||||||
|
dpInfo.Srcs = android.FirstUniqueStrings(dpInfo.Srcs)
|
||||||
|
|
||||||
|
dpInfo.Global_Common_Flags = parseCompilerCCParameters(ctx, ccModule.flags.Global.CommonFlags)
|
||||||
|
dpInfo.Local_Common_Flags = parseCompilerCCParameters(ctx, ccModule.flags.Local.CommonFlags)
|
||||||
|
dpInfo.Global_C_flags = parseCompilerCCParameters(ctx, ccModule.flags.Global.CFlags)
|
||||||
|
dpInfo.Local_C_flags = parseCompilerCCParameters(ctx, ccModule.flags.Local.CFlags)
|
||||||
|
dpInfo.Global_C_only_flags = parseCompilerCCParameters(ctx, ccModule.flags.Global.ConlyFlags)
|
||||||
|
dpInfo.Local_C_only_flags = parseCompilerCCParameters(ctx, ccModule.flags.Local.ConlyFlags)
|
||||||
|
dpInfo.Global_Cpp_flags = parseCompilerCCParameters(ctx, ccModule.flags.Global.CppFlags)
|
||||||
|
dpInfo.Local_Cpp_flags = parseCompilerCCParameters(ctx, ccModule.flags.Local.CppFlags)
|
||||||
|
dpInfo.System_include_flags = parseCompilerCCParameters(ctx, ccModule.flags.SystemIncludeFlags)
|
||||||
|
|
||||||
|
dpInfo.Module_name = name
|
||||||
|
|
||||||
|
moduleInfos[name] = dpInfo
|
||||||
|
}
|
||||||
|
|
||||||
|
type Deal struct {
|
||||||
|
Name string
|
||||||
|
ideInfo ccIdeInfo
|
||||||
|
}
|
||||||
|
|
||||||
|
type Deals []Deal
|
||||||
|
|
||||||
|
// Ensure it satisfies sort.Interface
|
||||||
|
func (d Deals) Len() int { return len(d) }
|
||||||
|
func (d Deals) Less(i, j int) bool { return d[i].Name < d[j].Name }
|
||||||
|
func (d Deals) Swap(i, j int) { d[i], d[j] = d[j], d[i] }
|
||||||
|
|
||||||
|
func sortMap(moduleInfos map[string]ccIdeInfo) map[string]ccIdeInfo {
|
||||||
|
var deals Deals
|
||||||
|
for k, v := range moduleInfos {
|
||||||
|
deals = append(deals, Deal{k, v})
|
||||||
|
}
|
||||||
|
|
||||||
|
sort.Sort(deals)
|
||||||
|
|
||||||
|
m := map[string]ccIdeInfo{}
|
||||||
|
for _, d := range deals {
|
||||||
|
m[d.Name] = d.ideInfo
|
||||||
|
}
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
|
||||||
|
func createJsonFile(moduleDeps ccDeps, ccfpath string) error {
|
||||||
|
file, err := os.Create(ccfpath)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Failed to create file: %s, relative: %v", ccdepsJsonFileName, err)
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
moduleDeps.Modules = sortMap(moduleDeps.Modules)
|
||||||
|
buf, err := json.MarshalIndent(moduleDeps, "", "\t")
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Write file failed: %s, relative: %v", ccdepsJsonFileName, err)
|
||||||
|
}
|
||||||
|
fmt.Fprintf(file, string(buf))
|
||||||
|
return nil
|
||||||
|
}
|
Loading…
Reference in a new issue