blob: b61f2a8be5a6db12b67acb601b5da6b73dbb2b64 [file] [log] [blame]
Jesse Pai4d336662019-09-13 17:08:52 -07001package cc
2
3import (
4 "fmt"
5 "sort"
6 "strings"
7
8 "github.com/google/blueprint/proptools"
9
10 "android/soong/android"
11)
12
13func init() {
14 android.RegisterSingletonType("cflag_artifacts_text", cflagArtifactsTextFactory)
15}
16
17var (
18 TrackedCFlags = []string{
19 "-Wall",
20 "-Werror",
21 "-Wextra",
22 "-Wthread-safety",
23 "-O3",
24 }
25
26 TrackedCFlagsDir = []string{
27 "device/google/",
28 "vendor/google/",
29 }
30)
31
32const FileBP = 50
33
34// Stores output files.
35type cflagArtifactsText struct {
36 interOutputs map[string]android.WritablePaths
37 outputs android.WritablePaths
38}
39
40// allowedDir verifies if the directory/project is part of the TrackedCFlagsDir
41// filter.
42func allowedDir(subdir string) bool {
43 subdir += "/"
44 for _, prefix := range TrackedCFlagsDir {
45 if strings.HasPrefix(subdir, prefix) {
46 return true
47 }
48 }
49 return false
50}
51
52func (s *cflagArtifactsText) genFlagFilename(flag string) string {
53 return fmt.Sprintf("module_cflags%s.txt", flag)
54}
55
56// incrementFile is used to generate an output path object with the passed in flag
57// and part number.
58// e.g. FLAG + part # -> out/soong/cflags/module_cflags-FLAG.txt.0
59func (s *cflagArtifactsText) incrementFile(ctx android.SingletonContext,
60 flag string, part int) (string, android.OutputPath) {
61
62 filename := fmt.Sprintf("%s.%d", s.genFlagFilename(flag), part)
63 filepath := android.PathForOutput(ctx, "cflags", filename)
64 s.interOutputs[flag] = append(s.interOutputs[flag], filepath)
65 return filename, filepath
66}
67
68// GenCFlagArtifactParts is used to generate the build rules which produce the
69// intermediary files for each desired C Flag artifact
70// e.g. module_cflags-FLAG.txt.0, module_cflags-FLAG.txt.1, ...
71func (s *cflagArtifactsText) GenCFlagArtifactParts(ctx android.SingletonContext,
72 flag string, using bool, modules []string, part int) int {
73
74 cleanedName := strings.Replace(flag, "=", "_", -1)
75 filename, filepath := s.incrementFile(ctx, cleanedName, part)
76 rule := android.NewRuleBuilder()
77 rule.Command().Textf("rm -f %s", filepath.String())
78
79 if using {
80 rule.Command().
81 Textf("echo '# Modules using %s'", flag).
82 FlagWithOutput(">> ", filepath)
83 } else {
84 rule.Command().
85 Textf("echo '# Modules not using %s'", flag).
86 FlagWithOutput(">> ", filepath)
87 }
88
89 length := len(modules)
90
91 if length == 0 {
92 rule.Build(pctx, ctx, filename, "gen "+filename)
93 part++
94 }
95
96 // Following loop splits the module list for each tracked C Flag into
97 // chunks of length FileBP (file breakpoint) and generates a partial artifact
98 // (intermediary file) build rule for each split.
99 moduleShards := android.ShardStrings(modules, FileBP)
100 for index, shard := range moduleShards {
101 rule.Command().
102 Textf("for m in %s; do echo $m",
103 strings.Join(proptools.ShellEscapeList(shard), " ")).
104 FlagWithOutput(">> ", filepath).
105 Text("; done")
106 rule.Build(pctx, ctx, filename, "gen "+filename)
107
108 if index+1 != len(moduleShards) {
109 filename, filepath = s.incrementFile(ctx, cleanedName, part+index+1)
110 rule = android.NewRuleBuilder()
111 rule.Command().Textf("rm -f %s", filepath.String())
112 }
113 }
114
115 return part + len(moduleShards)
116}
117
118// GenCFlagArtifacts is used to generate build rules which combine the
119// intermediary files of a specific tracked flag into a single C Flag artifact
120// for each tracked flag.
121// e.g. module_cflags-FLAG.txt.0 + module_cflags-FLAG.txt.1 = module_cflags-FLAG.txt
122func (s *cflagArtifactsText) GenCFlagArtifacts(ctx android.SingletonContext) {
123 // Scans through s.interOutputs and creates a build rule for each tracked C
124 // Flag that concatenates the associated intermediary file into a single
125 // artifact.
126 for _, flag := range TrackedCFlags {
127 // Generate build rule to combine related intermediary files into a
128 // C Flag artifact
129 rule := android.NewRuleBuilder()
130 filename := s.genFlagFilename(flag)
131 outputpath := android.PathForOutput(ctx, "cflags", filename)
132 rule.Command().
133 Text("cat").
134 Inputs(s.interOutputs[flag].Paths()).
135 FlagWithOutput("> ", outputpath)
136 rule.Build(pctx, ctx, filename, "gen "+filename)
137 s.outputs = append(s.outputs, outputpath)
138 }
139}
140
141func (s *cflagArtifactsText) GenerateBuildActions(ctx android.SingletonContext) {
142 modulesWithCFlag := make(map[string][]string)
143
144 // Scan through all modules, selecting the ones that are part of the filter,
145 // and then storing into a map which tracks whether or not tracked C flag is
146 // used or not.
147 ctx.VisitAllModules(func(module android.Module) {
148 if ccModule, ok := module.(*Module); ok {
149 if allowedDir(ctx.ModuleDir(ccModule)) {
Colin Cross4af21ed2019-11-04 09:37:55 -0800150 cflags := ccModule.flags.Local.CFlags
151 cppflags := ccModule.flags.Local.CppFlags
Jesse Pai4d336662019-09-13 17:08:52 -0700152 module := fmt.Sprintf("%s:%s (%s)",
153 ctx.BlueprintFile(ccModule),
154 ctx.ModuleName(ccModule),
155 ctx.ModuleSubDir(ccModule))
156 for _, flag := range TrackedCFlags {
157 if inList(flag, cflags) || inList(flag, cppflags) {
158 modulesWithCFlag[flag] = append(modulesWithCFlag[flag], module)
159 } else {
160 modulesWithCFlag["!"+flag] = append(modulesWithCFlag["!"+flag], module)
161 }
162 }
163 }
164 }
165 })
166
167 // Traversing map and setting up rules to produce intermediary files which
168 // contain parts of each expected C Flag artifact.
169 for _, flag := range TrackedCFlags {
170 sort.Strings(modulesWithCFlag[flag])
171 part := s.GenCFlagArtifactParts(ctx, flag, true, modulesWithCFlag[flag], 0)
172 sort.Strings(modulesWithCFlag["!"+flag])
173 s.GenCFlagArtifactParts(ctx, flag, false, modulesWithCFlag["!"+flag], part)
174 }
175
176 // Combine intermediary files into a single C Flag artifact.
177 s.GenCFlagArtifacts(ctx)
178}
179
180func cflagArtifactsTextFactory() android.Singleton {
181 return &cflagArtifactsText{
182 interOutputs: make(map[string]android.WritablePaths),
183 }
184}
185
186func (s *cflagArtifactsText) MakeVars(ctx android.MakeVarsContext) {
187 ctx.Strict("SOONG_MODULES_CFLAG_ARTIFACTS", strings.Join(s.outputs.Strings(), " "))
188}