Support per-module MakeVars
This allows setting per-module make variables earlier in the build,
particularly for prebuilt_build_tool users like LEX/M4/BISON. I moved
filegroup over because it's a simpler common interface, but it doesn't
strictly need it.
With this, the last user of the hardcoded cc.m4Cmd variable is gone.
Test: Inspect out/soong/make_vars-*.mk, out/soong/late-*.mk
Test: treehugger
Change-Id: I195b688131feac0c100c338a0749368aa5d50f4f
diff --git a/android/filegroup.go b/android/filegroup.go
index ec522fc..68311e3 100644
--- a/android/filegroup.go
+++ b/android/filegroup.go
@@ -15,9 +15,7 @@
package android
import (
- "io"
"strings"
- "text/template"
)
func init() {
@@ -71,23 +69,8 @@
return append(Paths{}, fg.srcs...)
}
-var androidMkTemplate = template.Must(template.New("filegroup").Parse(`
-ifdef {{.makeVar}}
- $(error variable {{.makeVar}} set by soong module is already set in make)
-endif
-{{.makeVar}} := {{.value}}
-.KATI_READONLY := {{.makeVar}}
-`))
-
-func (fg *fileGroup) AndroidMk() AndroidMkData {
- return AndroidMkData{
- Custom: func(w io.Writer, name, prefix, moduleDir string, data AndroidMkData) {
- if makeVar := String(fg.properties.Export_to_make_var); makeVar != "" {
- androidMkTemplate.Execute(w, map[string]string{
- "makeVar": makeVar,
- "value": strings.Join(fg.srcs.Strings(), " "),
- })
- }
- },
+func (fg *fileGroup) MakeVars(ctx MakeVarsModuleContext) {
+ if makeVar := String(fg.properties.Export_to_make_var); makeVar != "" {
+ ctx.StrictRaw(makeVar, strings.Join(fg.srcs.Strings(), " "))
}
}
diff --git a/android/makevars.go b/android/makevars.go
index ff7c8e4..86f4b42 100644
--- a/android/makevars.go
+++ b/android/makevars.go
@@ -17,6 +17,7 @@
import (
"bytes"
"fmt"
+ "sort"
"strconv"
"strings"
@@ -34,43 +35,16 @@
}
///////////////////////////////////////////////////////////////////////////////
-// Interface for other packages to use to declare make variables
-type MakeVarsContext interface {
+
+// BaseMakeVarsContext contains the common functions for other packages to use
+// to declare make variables
+type BaseMakeVarsContext interface {
Config() Config
DeviceConfig() DeviceConfig
AddNinjaFileDeps(deps ...string)
- ModuleName(module blueprint.Module) string
- ModuleDir(module blueprint.Module) string
- ModuleSubDir(module blueprint.Module) string
- ModuleType(module blueprint.Module) string
- BlueprintFile(module blueprint.Module) string
-
- ModuleErrorf(module blueprint.Module, format string, args ...interface{})
- Errorf(format string, args ...interface{})
Failed() bool
- VisitAllModules(visit func(Module))
- VisitAllModulesIf(pred func(Module) bool, visit func(Module))
-
- // Verify the make variable matches the Soong version, fail the build
- // if it does not. If the make variable is empty, just set it.
- Strict(name, ninjaStr string)
- // Check to see if the make variable matches the Soong version, warn if
- // it does not. If the make variable is empty, just set it.
- Check(name, ninjaStr string)
-
- // These are equivalent to the above, but sort the make and soong
- // variables before comparing them. They also show the unique entries
- // in each list when displaying the difference, instead of the entire
- // string.
- StrictSorted(name, ninjaStr string)
- CheckSorted(name, ninjaStr string)
-
- // Evaluates a ninja string and returns the result. Used if more
- // complicated modification needs to happen before giving it to Make.
- Eval(ninjaStr string) (string, error)
-
// These are equivalent to Strict and Check, but do not attempt to
// evaluate the values before writing them to the Makefile. They can
// be used when all ninja variables have already been evaluated through
@@ -108,6 +82,48 @@
DistForGoalsWithFilename(goals []string, path Path, filename string)
}
+// MakeVarsContext contains the set of functions available for MakeVarsProvider
+// and SingletonMakeVarsProvider implementations.
+type MakeVarsContext interface {
+ BaseMakeVarsContext
+
+ ModuleName(module blueprint.Module) string
+ ModuleDir(module blueprint.Module) string
+ ModuleSubDir(module blueprint.Module) string
+ ModuleType(module blueprint.Module) string
+ BlueprintFile(module blueprint.Module) string
+
+ ModuleErrorf(module blueprint.Module, format string, args ...interface{})
+ Errorf(format string, args ...interface{})
+
+ VisitAllModules(visit func(Module))
+ VisitAllModulesIf(pred func(Module) bool, visit func(Module))
+
+ // Verify the make variable matches the Soong version, fail the build
+ // if it does not. If the make variable is empty, just set it.
+ Strict(name, ninjaStr string)
+ // Check to see if the make variable matches the Soong version, warn if
+ // it does not. If the make variable is empty, just set it.
+ Check(name, ninjaStr string)
+
+ // These are equivalent to the above, but sort the make and soong
+ // variables before comparing them. They also show the unique entries
+ // in each list when displaying the difference, instead of the entire
+ // string.
+ StrictSorted(name, ninjaStr string)
+ CheckSorted(name, ninjaStr string)
+
+ // Evaluates a ninja string and returns the result. Used if more
+ // complicated modification needs to happen before giving it to Make.
+ Eval(ninjaStr string) (string, error)
+}
+
+// MakeVarsModuleContext contains the set of functions available for modules
+// implementing the ModuleMakeVarsProvider interface.
+type MakeVarsModuleContext interface {
+ BaseMakeVarsContext
+}
+
var _ PathContext = MakeVarsContext(nil)
type MakeVarsProvider func(ctx MakeVarsContext)
@@ -135,6 +151,14 @@
return func(ctx MakeVarsContext) { singleton.MakeVars(ctx) }
}
+// ModuleMakeVarsProvider is a Module with an extra method to provide extra values to be exported to Make.
+type ModuleMakeVarsProvider interface {
+ Module
+
+ // MakeVars uses a MakeVarsModuleContext to provide extra values to be exported to Make.
+ MakeVars(ctx MakeVarsModuleContext)
+}
+
///////////////////////////////////////////////////////////////////////////////
func makeVarsSingletonFunc() Singleton {
@@ -209,10 +233,45 @@
dists = append(dists, mctx.dists...)
}
+ ctx.VisitAllModules(func(m Module) {
+ if provider, ok := m.(ModuleMakeVarsProvider); ok {
+ mctx := &makeVarsContext{
+ SingletonContext: ctx,
+ }
+
+ provider.MakeVars(mctx)
+
+ vars = append(vars, mctx.vars...)
+ phonies = append(phonies, mctx.phonies...)
+ dists = append(dists, mctx.dists...)
+ }
+ })
+
if ctx.Failed() {
return
}
+ sort.Slice(vars, func(i, j int) bool {
+ return vars[i].name < vars[j].name
+ })
+ sort.Slice(phonies, func(i, j int) bool {
+ return phonies[i].name < phonies[j].name
+ })
+ lessArr := func(a, b []string) bool {
+ if len(a) == len(b) {
+ for i := range a {
+ if a[i] < b[i] {
+ return true
+ }
+ }
+ return false
+ }
+ return len(a) < len(b)
+ }
+ sort.Slice(dists, func(i, j int) bool {
+ return lessArr(dists[i].goals, dists[j].goals) || lessArr(dists[i].paths, dists[j].paths)
+ })
+
outBytes := s.writeVars(vars)
if err := pathtools.WriteFileIfChanged(outFile, outBytes, 0666); err != nil {
diff --git a/android/prebuilt_build_tool.go b/android/prebuilt_build_tool.go
index a9f29ef..561771b 100644
--- a/android/prebuilt_build_tool.go
+++ b/android/prebuilt_build_tool.go
@@ -29,6 +29,10 @@
// Extra files that should trigger rules using this tool to rebuild
Deps []string `android:"path,arch_variant"`
+
+ // Create a make variable with the specified name that contains the path to
+ // this prebuilt built tool, relative to the root of the source tree.
+ Export_to_make_var *string
}
type prebuiltBuildTool struct {
@@ -81,6 +85,12 @@
return t.toolPath
}
+func (t *prebuiltBuildTool) MakeVars(ctx MakeVarsModuleContext) {
+ if makeVar := String(t.properties.Export_to_make_var); makeVar != "" {
+ ctx.StrictRaw(makeVar, t.toolPath.String())
+ }
+}
+
var _ HostToolProvider = &prebuiltBuildTool{}
// prebuilt_build_tool is to declare prebuilts to be used during the build, particularly for use