Reland "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 (which will
come in a later CL). I moved filegroup over because it's a simpler
common interface, but it doesn't strictly need it.

Test: Inspect out/soong/make_vars-*.mk, out/soong/late-*.mk
Test: treehugger
Change-Id: I38631129d82b0aad2438e83610bb6a97568bf932
This commit is contained in:
Dan Willemsen
2020-07-17 19:28:53 -07:00
parent 217a1e406e
commit 6a6478d49e
2 changed files with 93 additions and 51 deletions

View File

@@ -15,9 +15,7 @@
package android package android
import ( import (
"io"
"strings" "strings"
"text/template"
) )
func init() { func init() {
@@ -71,23 +69,8 @@ func (fg *fileGroup) Srcs() Paths {
return append(Paths{}, fg.srcs...) return append(Paths{}, fg.srcs...)
} }
var androidMkTemplate = template.Must(template.New("filegroup").Parse(` func (fg *fileGroup) MakeVars(ctx MakeVarsModuleContext) {
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 != "" { if makeVar := String(fg.properties.Export_to_make_var); makeVar != "" {
androidMkTemplate.Execute(w, map[string]string{ ctx.StrictRaw(makeVar, strings.Join(fg.srcs.Strings(), " "))
"makeVar": makeVar,
"value": strings.Join(fg.srcs.Strings(), " "),
})
}
},
} }
} }

View File

@@ -17,6 +17,7 @@ package android
import ( import (
"bytes" "bytes"
"fmt" "fmt"
"sort"
"strconv" "strconv"
"strings" "strings"
@@ -34,43 +35,16 @@ func androidMakeVarsProvider(ctx MakeVarsContext) {
} }
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// 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 Config() Config
DeviceConfig() DeviceConfig DeviceConfig() DeviceConfig
AddNinjaFileDeps(deps ...string) 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 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 // These are equivalent to Strict and Check, but do not attempt to
// evaluate the values before writing them to the Makefile. They can // evaluate the values before writing them to the Makefile. They can
// be used when all ninja variables have already been evaluated through // be used when all ninja variables have already been evaluated through
@@ -108,6 +82,48 @@ type MakeVarsContext interface {
DistForGoalsWithFilename(goals []string, path Path, filename string) 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) var _ PathContext = MakeVarsContext(nil)
type MakeVarsProvider func(ctx MakeVarsContext) type MakeVarsProvider func(ctx MakeVarsContext)
@@ -135,6 +151,14 @@ func SingletonmakeVarsProviderAdapter(singleton SingletonMakeVarsProvider) MakeV
return func(ctx MakeVarsContext) { singleton.MakeVars(ctx) } 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 { func makeVarsSingletonFunc() Singleton {
@@ -209,10 +233,45 @@ func (s *makeVarsSingleton) GenerateBuildActions(ctx SingletonContext) {
dists = append(dists, mctx.dists...) 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() { if ctx.Failed() {
return 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) outBytes := s.writeVars(vars)
if err := pathtools.WriteFileIfChanged(outFile, outBytes, 0666); err != nil { if err := pathtools.WriteFileIfChanged(outFile, outBytes, 0666); err != nil {