Creation of C Flags Build Variables
Modifications made to soong/cc to look for specific C Flags used by
Android modules and store name of module into a build variable array.
Bug: 140442588
Test: Executed m dist and presubmit
Change-Id: If46a11462369c43bbcd445156aff0641514c58b1
diff --git a/cc/cflag_artifacts.go b/cc/cflag_artifacts.go
new file mode 100644
index 0000000..9ed3876
--- /dev/null
+++ b/cc/cflag_artifacts.go
@@ -0,0 +1,188 @@
+package cc
+
+import (
+ "fmt"
+ "sort"
+ "strings"
+
+ "github.com/google/blueprint/proptools"
+
+ "android/soong/android"
+)
+
+func init() {
+ android.RegisterSingletonType("cflag_artifacts_text", cflagArtifactsTextFactory)
+}
+
+var (
+ TrackedCFlags = []string{
+ "-Wall",
+ "-Werror",
+ "-Wextra",
+ "-Wthread-safety",
+ "-O3",
+ }
+
+ TrackedCFlagsDir = []string{
+ "device/google/",
+ "vendor/google/",
+ }
+)
+
+const FileBP = 50
+
+// Stores output files.
+type cflagArtifactsText struct {
+ interOutputs map[string]android.WritablePaths
+ outputs android.WritablePaths
+}
+
+// allowedDir verifies if the directory/project is part of the TrackedCFlagsDir
+// filter.
+func allowedDir(subdir string) bool {
+ subdir += "/"
+ for _, prefix := range TrackedCFlagsDir {
+ if strings.HasPrefix(subdir, prefix) {
+ return true
+ }
+ }
+ return false
+}
+
+func (s *cflagArtifactsText) genFlagFilename(flag string) string {
+ return fmt.Sprintf("module_cflags%s.txt", flag)
+}
+
+// incrementFile is used to generate an output path object with the passed in flag
+// and part number.
+// e.g. FLAG + part # -> out/soong/cflags/module_cflags-FLAG.txt.0
+func (s *cflagArtifactsText) incrementFile(ctx android.SingletonContext,
+ flag string, part int) (string, android.OutputPath) {
+
+ filename := fmt.Sprintf("%s.%d", s.genFlagFilename(flag), part)
+ filepath := android.PathForOutput(ctx, "cflags", filename)
+ s.interOutputs[flag] = append(s.interOutputs[flag], filepath)
+ return filename, filepath
+}
+
+// GenCFlagArtifactParts is used to generate the build rules which produce the
+// intermediary files for each desired C Flag artifact
+// e.g. module_cflags-FLAG.txt.0, module_cflags-FLAG.txt.1, ...
+func (s *cflagArtifactsText) GenCFlagArtifactParts(ctx android.SingletonContext,
+ flag string, using bool, modules []string, part int) int {
+
+ cleanedName := strings.Replace(flag, "=", "_", -1)
+ filename, filepath := s.incrementFile(ctx, cleanedName, part)
+ rule := android.NewRuleBuilder()
+ rule.Command().Textf("rm -f %s", filepath.String())
+
+ if using {
+ rule.Command().
+ Textf("echo '# Modules using %s'", flag).
+ FlagWithOutput(">> ", filepath)
+ } else {
+ rule.Command().
+ Textf("echo '# Modules not using %s'", flag).
+ FlagWithOutput(">> ", filepath)
+ }
+
+ length := len(modules)
+
+ if length == 0 {
+ rule.Build(pctx, ctx, filename, "gen "+filename)
+ part++
+ }
+
+ // Following loop splits the module list for each tracked C Flag into
+ // chunks of length FileBP (file breakpoint) and generates a partial artifact
+ // (intermediary file) build rule for each split.
+ moduleShards := android.ShardStrings(modules, FileBP)
+ for index, shard := range moduleShards {
+ rule.Command().
+ Textf("for m in %s; do echo $m",
+ strings.Join(proptools.ShellEscapeList(shard), " ")).
+ FlagWithOutput(">> ", filepath).
+ Text("; done")
+ rule.Build(pctx, ctx, filename, "gen "+filename)
+
+ if index+1 != len(moduleShards) {
+ filename, filepath = s.incrementFile(ctx, cleanedName, part+index+1)
+ rule = android.NewRuleBuilder()
+ rule.Command().Textf("rm -f %s", filepath.String())
+ }
+ }
+
+ return part + len(moduleShards)
+}
+
+// GenCFlagArtifacts is used to generate build rules which combine the
+// intermediary files of a specific tracked flag into a single C Flag artifact
+// for each tracked flag.
+// e.g. module_cflags-FLAG.txt.0 + module_cflags-FLAG.txt.1 = module_cflags-FLAG.txt
+func (s *cflagArtifactsText) GenCFlagArtifacts(ctx android.SingletonContext) {
+ // Scans through s.interOutputs and creates a build rule for each tracked C
+ // Flag that concatenates the associated intermediary file into a single
+ // artifact.
+ for _, flag := range TrackedCFlags {
+ // Generate build rule to combine related intermediary files into a
+ // C Flag artifact
+ rule := android.NewRuleBuilder()
+ filename := s.genFlagFilename(flag)
+ outputpath := android.PathForOutput(ctx, "cflags", filename)
+ rule.Command().
+ Text("cat").
+ Inputs(s.interOutputs[flag].Paths()).
+ FlagWithOutput("> ", outputpath)
+ rule.Build(pctx, ctx, filename, "gen "+filename)
+ s.outputs = append(s.outputs, outputpath)
+ }
+}
+
+func (s *cflagArtifactsText) GenerateBuildActions(ctx android.SingletonContext) {
+ modulesWithCFlag := make(map[string][]string)
+
+ // Scan through all modules, selecting the ones that are part of the filter,
+ // and then storing into a map which tracks whether or not tracked C flag is
+ // used or not.
+ ctx.VisitAllModules(func(module android.Module) {
+ if ccModule, ok := module.(*Module); ok {
+ if allowedDir(ctx.ModuleDir(ccModule)) {
+ cflags := ccModule.flags.CFlags
+ cppflags := ccModule.flags.CppFlags
+ module := fmt.Sprintf("%s:%s (%s)",
+ ctx.BlueprintFile(ccModule),
+ ctx.ModuleName(ccModule),
+ ctx.ModuleSubDir(ccModule))
+ for _, flag := range TrackedCFlags {
+ if inList(flag, cflags) || inList(flag, cppflags) {
+ modulesWithCFlag[flag] = append(modulesWithCFlag[flag], module)
+ } else {
+ modulesWithCFlag["!"+flag] = append(modulesWithCFlag["!"+flag], module)
+ }
+ }
+ }
+ }
+ })
+
+ // Traversing map and setting up rules to produce intermediary files which
+ // contain parts of each expected C Flag artifact.
+ for _, flag := range TrackedCFlags {
+ sort.Strings(modulesWithCFlag[flag])
+ part := s.GenCFlagArtifactParts(ctx, flag, true, modulesWithCFlag[flag], 0)
+ sort.Strings(modulesWithCFlag["!"+flag])
+ s.GenCFlagArtifactParts(ctx, flag, false, modulesWithCFlag["!"+flag], part)
+ }
+
+ // Combine intermediary files into a single C Flag artifact.
+ s.GenCFlagArtifacts(ctx)
+}
+
+func cflagArtifactsTextFactory() android.Singleton {
+ return &cflagArtifactsText{
+ interOutputs: make(map[string]android.WritablePaths),
+ }
+}
+
+func (s *cflagArtifactsText) MakeVars(ctx android.MakeVarsContext) {
+ ctx.Strict("SOONG_MODULES_CFLAG_ARTIFACTS", strings.Join(s.outputs.Strings(), " "))
+}