File: cflag_artifacts.go

package info (click to toggle)
golang-android-soong 0.0~git20201014.17e97d9-4
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, forky, sid, trixie
  • size: 7,680 kB
  • sloc: python: 3,000; sh: 1,780; cpp: 66; makefile: 5
file content (183 lines) | stat: -rw-r--r-- 5,767 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
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 += "/"
	return android.HasAnyPrefix(subdir, TrackedCFlagsDir)
}

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.Local.CFlags
				cppflags := ccModule.flags.Local.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(), " "))
}