Stop determining package names from the call stack.
This change replaces the automatic caller package divination with a PackageContext object that must be explicitly passed in by callers. Change-Id: I139be29ecf75a7cf8488b3958dee5e44363acc22
This commit is contained in:
parent
0c35b2db92
commit
2fb2095caa
11 changed files with 306 additions and 283 deletions
|
@ -3,13 +3,13 @@ bootstrap_go_package {
|
|||
deps: ["blueprint-parser"],
|
||||
pkgPath: "blueprint",
|
||||
srcs: ["blueprint/context.go",
|
||||
"blueprint/globals.go",
|
||||
"blueprint/live_tracker.go",
|
||||
"blueprint/mangle.go",
|
||||
"blueprint/module_ctx.go",
|
||||
"blueprint/ninja_defs.go",
|
||||
"blueprint/ninja_strings.go",
|
||||
"blueprint/ninja_writer.go",
|
||||
"blueprint/package_ctx.go",
|
||||
"blueprint/scope.go",
|
||||
"blueprint/singleton_ctx.go",
|
||||
"blueprint/unpack.go"],
|
||||
|
|
|
@ -11,11 +11,13 @@ import (
|
|||
const bootstrapDir = ".bootstrap"
|
||||
|
||||
var (
|
||||
gcCmd = blueprint.StaticVariable("gcCmd", "$goToolDir/${GoChar}g")
|
||||
packCmd = blueprint.StaticVariable("packCmd", "$goToolDir/pack")
|
||||
linkCmd = blueprint.StaticVariable("linkCmd", "$goToolDir/${GoChar}l")
|
||||
pctx = blueprint.NewPackageContext("blueprint/bootstrap")
|
||||
|
||||
gc = blueprint.StaticRule("gc",
|
||||
gcCmd = pctx.StaticVariable("gcCmd", "$goToolDir/${GoChar}g")
|
||||
packCmd = pctx.StaticVariable("packCmd", "$goToolDir/pack")
|
||||
linkCmd = pctx.StaticVariable("linkCmd", "$goToolDir/${GoChar}l")
|
||||
|
||||
gc = pctx.StaticRule("gc",
|
||||
blueprint.RuleParams{
|
||||
Command: "GOROOT='$GoRoot' $gcCmd -o $out -p $pkgPath -complete " +
|
||||
"$incFlags $in",
|
||||
|
@ -23,35 +25,35 @@ var (
|
|||
},
|
||||
"pkgPath", "incFlags")
|
||||
|
||||
pack = blueprint.StaticRule("pack",
|
||||
pack = pctx.StaticRule("pack",
|
||||
blueprint.RuleParams{
|
||||
Command: "GOROOT='$GoRoot' $packCmd grcP $prefix $out $in",
|
||||
Description: "pack $out",
|
||||
},
|
||||
"prefix")
|
||||
|
||||
link = blueprint.StaticRule("link",
|
||||
link = pctx.StaticRule("link",
|
||||
blueprint.RuleParams{
|
||||
Command: "GOROOT='$GoRoot' $linkCmd -o $out $libDirFlags $in",
|
||||
Description: "${GoChar}l $out",
|
||||
},
|
||||
"libDirFlags")
|
||||
|
||||
cp = blueprint.StaticRule("cp",
|
||||
cp = pctx.StaticRule("cp",
|
||||
blueprint.RuleParams{
|
||||
Command: "cp $in $out",
|
||||
Description: "cp $out",
|
||||
},
|
||||
"generator")
|
||||
|
||||
bootstrap = blueprint.StaticRule("bootstrap",
|
||||
bootstrap = pctx.StaticRule("bootstrap",
|
||||
blueprint.RuleParams{
|
||||
Command: "$Bootstrap -i $in",
|
||||
Description: "bootstrap $in",
|
||||
Generator: true,
|
||||
})
|
||||
|
||||
rebootstrap = blueprint.StaticRule("rebootstrap",
|
||||
rebootstrap = pctx.StaticRule("rebootstrap",
|
||||
blueprint.RuleParams{
|
||||
// Ninja only re-invokes itself once when it regenerates a .ninja
|
||||
// file. For the re-bootstrap process we need that to happen twice,
|
||||
|
@ -70,7 +72,7 @@ var (
|
|||
})
|
||||
|
||||
// Work around a Ninja issue. See https://github.com/martine/ninja/pull/634
|
||||
phony = blueprint.StaticRule("phony",
|
||||
phony = pctx.StaticRule("phony",
|
||||
blueprint.RuleParams{
|
||||
Command: "# phony $out",
|
||||
Description: "phony $out",
|
||||
|
@ -209,14 +211,14 @@ func (g *goBinary) GenerateBuildActions(ctx blueprint.ModuleContext) {
|
|||
linkArgs["libDirFlags"] = strings.Join(libDirFlags, " ")
|
||||
}
|
||||
|
||||
ctx.Build(blueprint.BuildParams{
|
||||
ctx.Build(pctx, blueprint.BuildParams{
|
||||
Rule: link,
|
||||
Outputs: []string{aoutFile},
|
||||
Inputs: []string{archiveFile},
|
||||
Args: linkArgs,
|
||||
})
|
||||
|
||||
ctx.Build(blueprint.BuildParams{
|
||||
ctx.Build(pctx, blueprint.BuildParams{
|
||||
Rule: cp,
|
||||
Outputs: []string{binaryFile},
|
||||
Inputs: []string{aoutFile},
|
||||
|
@ -254,7 +256,7 @@ func buildGoPackage(ctx blueprint.ModuleContext, pkgRoot string,
|
|||
gcArgs["incFlags"] = strings.Join(incFlags, " ")
|
||||
}
|
||||
|
||||
ctx.Build(blueprint.BuildParams{
|
||||
ctx.Build(pctx, blueprint.BuildParams{
|
||||
Rule: gc,
|
||||
Outputs: []string{objFile},
|
||||
Inputs: srcFiles,
|
||||
|
@ -262,7 +264,7 @@ func buildGoPackage(ctx blueprint.ModuleContext, pkgRoot string,
|
|||
Args: gcArgs,
|
||||
})
|
||||
|
||||
ctx.Build(blueprint.BuildParams{
|
||||
ctx.Build(pctx, blueprint.BuildParams{
|
||||
Rule: pack,
|
||||
Outputs: []string{archiveFile},
|
||||
Inputs: []string{objFile},
|
||||
|
@ -284,7 +286,7 @@ func phonyGoTarget(ctx blueprint.ModuleContext, target string, srcs []string) {
|
|||
moduleDir := ctx.ModuleDir()
|
||||
srcs = pathtools.PrefixPaths(srcs, filepath.Join("$SrcDir", moduleDir))
|
||||
|
||||
ctx.Build(blueprint.BuildParams{
|
||||
ctx.Build(pctx, blueprint.BuildParams{
|
||||
Rule: phony,
|
||||
Outputs: []string{target},
|
||||
Inputs: srcs,
|
||||
|
@ -297,7 +299,7 @@ func phonyGoTarget(ctx blueprint.ModuleContext, target string, srcs []string) {
|
|||
// for each source file, which will cause Ninja to treat it as dirty if its
|
||||
// missing.
|
||||
for _, src := range srcs {
|
||||
ctx.Build(blueprint.BuildParams{
|
||||
ctx.Build(pctx, blueprint.BuildParams{
|
||||
Rule: blueprint.Phony,
|
||||
Outputs: []string{src},
|
||||
})
|
||||
|
@ -364,7 +366,7 @@ func (s *singleton) GenerateBuildActions(ctx blueprint.SingletonContext) {
|
|||
// file. Otherwise we occasionally get "warning: bad deps log signature
|
||||
// or version; starting over" messages from Ninja, presumably because
|
||||
// two Ninja processes try to write to the same log concurrently.
|
||||
ctx.SetBuildDir(bootstrapDir)
|
||||
ctx.SetBuildDir(pctx, bootstrapDir)
|
||||
|
||||
// We generate the depfile here that includes the dependencies for all
|
||||
// the Blueprints files that contribute to generating the big build
|
||||
|
@ -373,7 +375,7 @@ func (s *singleton) GenerateBuildActions(ctx blueprint.SingletonContext) {
|
|||
// bootstrap. Because the re-bootstrap rule's output is "build.ninja"
|
||||
// we need to force the depfile to have that as its "make target"
|
||||
// (recall that depfiles use a subset of the Makefile syntax).
|
||||
bigbp := ctx.Rule("bigbp",
|
||||
bigbp := ctx.Rule(pctx, "bigbp",
|
||||
blueprint.RuleParams{
|
||||
Command: fmt.Sprintf("%s %s -d %s -o $out $in",
|
||||
primaryBuilderFile, primaryBuilderExtraFlags,
|
||||
|
@ -382,7 +384,7 @@ func (s *singleton) GenerateBuildActions(ctx blueprint.SingletonContext) {
|
|||
Depfile: mainNinjaDepFile,
|
||||
})
|
||||
|
||||
ctx.Build(blueprint.BuildParams{
|
||||
ctx.Build(pctx, blueprint.BuildParams{
|
||||
Rule: bigbp,
|
||||
Outputs: []string{mainNinjaFile},
|
||||
Inputs: []string{topLevelBlueprints},
|
||||
|
@ -397,12 +399,12 @@ func (s *singleton) GenerateBuildActions(ctx blueprint.SingletonContext) {
|
|||
// We also need to add an implicit dependency on bootstrapNinjaFile so
|
||||
// that it gets generated as part of the bootstrap process.
|
||||
notAFile := filepath.Join(bootstrapDir, "notAFile")
|
||||
ctx.Build(blueprint.BuildParams{
|
||||
ctx.Build(pctx, blueprint.BuildParams{
|
||||
Rule: blueprint.Phony,
|
||||
Outputs: []string{notAFile},
|
||||
})
|
||||
|
||||
ctx.Build(blueprint.BuildParams{
|
||||
ctx.Build(pctx, blueprint.BuildParams{
|
||||
Rule: bootstrap,
|
||||
Outputs: []string{"build.ninja"},
|
||||
Inputs: []string{mainNinjaFile},
|
||||
|
@ -415,7 +417,7 @@ func (s *singleton) GenerateBuildActions(ctx blueprint.SingletonContext) {
|
|||
// file's mtime to match that of the current one. If they're different
|
||||
// then the new file will have a newer timestamp than the current one
|
||||
// and it will trigger a reboostrap by the non-boostrap build manifest.
|
||||
minibp := ctx.Rule("minibp",
|
||||
minibp := ctx.Rule(pctx, "minibp",
|
||||
blueprint.RuleParams{
|
||||
Command: fmt.Sprintf("%s -c $checkFile -d $out.d -o $out $in",
|
||||
minibpFile),
|
||||
|
@ -425,7 +427,7 @@ func (s *singleton) GenerateBuildActions(ctx blueprint.SingletonContext) {
|
|||
},
|
||||
"checkFile")
|
||||
|
||||
ctx.Build(blueprint.BuildParams{
|
||||
ctx.Build(pctx, blueprint.BuildParams{
|
||||
Rule: minibp,
|
||||
Outputs: []string{bootstrapNinjaFile},
|
||||
Inputs: []string{topLevelBlueprints},
|
||||
|
@ -445,7 +447,7 @@ func (s *singleton) GenerateBuildActions(ctx blueprint.SingletonContext) {
|
|||
// On top of that we need to use the depfile generated by the bigbp
|
||||
// rule. We do this by depending on that file and then setting up a
|
||||
// phony rule to generate it that uses the depfile.
|
||||
ctx.Build(blueprint.BuildParams{
|
||||
ctx.Build(pctx, blueprint.BuildParams{
|
||||
Rule: rebootstrap,
|
||||
Outputs: []string{"build.ninja"},
|
||||
Inputs: []string{"$BootstrapManifest"},
|
||||
|
@ -456,7 +458,7 @@ func (s *singleton) GenerateBuildActions(ctx blueprint.SingletonContext) {
|
|||
},
|
||||
})
|
||||
|
||||
ctx.Build(blueprint.BuildParams{
|
||||
ctx.Build(pctx, blueprint.BuildParams{
|
||||
Rule: phony,
|
||||
Outputs: []string{mainNinjaFile},
|
||||
Inputs: []string{topLevelBlueprints},
|
||||
|
@ -470,7 +472,7 @@ func (s *singleton) GenerateBuildActions(ctx blueprint.SingletonContext) {
|
|||
// the current bootstrap manifest. We enable the Ninja "generator"
|
||||
// behavior so that Ninja doesn't invoke this build just because it's
|
||||
// missing a command line log entry for the bootstrap manifest.
|
||||
ctx.Build(blueprint.BuildParams{
|
||||
ctx.Build(pctx, blueprint.BuildParams{
|
||||
Rule: cp,
|
||||
Outputs: []string{"$BootstrapManifest"},
|
||||
Inputs: []string{bootstrapNinjaFile},
|
||||
|
@ -483,7 +485,7 @@ func (s *singleton) GenerateBuildActions(ctx blueprint.SingletonContext) {
|
|||
// This is a standalone Blueprint build, so we copy the minibp
|
||||
// binary to the "bin" directory to make it easier to find.
|
||||
finalMinibp := filepath.Join("bin", primaryBuilderName)
|
||||
ctx.Build(blueprint.BuildParams{
|
||||
ctx.Build(pctx, blueprint.BuildParams{
|
||||
Rule: cp,
|
||||
Inputs: []string{primaryBuilderFile},
|
||||
Outputs: []string{finalMinibp},
|
||||
|
|
|
@ -1,23 +1,19 @@
|
|||
package bootstrap
|
||||
|
||||
import (
|
||||
"blueprint"
|
||||
)
|
||||
|
||||
var (
|
||||
// These variables are the only configuration needed by the boostrap
|
||||
// modules. They are always set to the variable name enclosed in "@@" so
|
||||
// that their values can be easily replaced in the generated Ninja file.
|
||||
SrcDir = blueprint.StaticVariable("SrcDir", "@@SrcDir@@")
|
||||
GoRoot = blueprint.StaticVariable("GoRoot", "@@GoRoot@@")
|
||||
GoOS = blueprint.StaticVariable("GoOS", "@@GoOS@@")
|
||||
GoArch = blueprint.StaticVariable("GoArch", "@@GoArch@@")
|
||||
GoChar = blueprint.StaticVariable("GoChar", "@@GoChar@@")
|
||||
Bootstrap = blueprint.StaticVariable("Bootstrap", "@@Bootstrap@@")
|
||||
BootstrapManifest = blueprint.StaticVariable("BootstrapManifest",
|
||||
SrcDir = pctx.StaticVariable("SrcDir", "@@SrcDir@@")
|
||||
GoRoot = pctx.StaticVariable("GoRoot", "@@GoRoot@@")
|
||||
GoOS = pctx.StaticVariable("GoOS", "@@GoOS@@")
|
||||
GoArch = pctx.StaticVariable("GoArch", "@@GoArch@@")
|
||||
GoChar = pctx.StaticVariable("GoChar", "@@GoChar@@")
|
||||
Bootstrap = pctx.StaticVariable("Bootstrap", "@@Bootstrap@@")
|
||||
BootstrapManifest = pctx.StaticVariable("BootstrapManifest",
|
||||
"@@BootstrapManifest@@")
|
||||
|
||||
goToolDir = blueprint.StaticVariable("goToolDir",
|
||||
goToolDir = pctx.StaticVariable("goToolDir",
|
||||
"$GoRoot/pkg/tool/${GoOS}_$GoArch")
|
||||
)
|
||||
|
||||
|
|
|
@ -58,7 +58,7 @@ type Context struct {
|
|||
ignoreUnknownModuleTypes bool
|
||||
|
||||
// set during PrepareBuildActions
|
||||
pkgNames map[*pkg]string
|
||||
pkgNames map[*PackageContext]string
|
||||
globalVariables map[Variable]*ninjaString
|
||||
globalPools map[Pool]*poolDef
|
||||
globalRules map[Rule]*ruleDef
|
||||
|
@ -1107,59 +1107,59 @@ func (c *Context) setBuildDir(value *ninjaString) {
|
|||
}
|
||||
|
||||
func (c *Context) makeUniquePackageNames(
|
||||
liveGlobals *liveTracker) map[*pkg]string {
|
||||
liveGlobals *liveTracker) map[*PackageContext]string {
|
||||
|
||||
pkgs := make(map[string]*pkg)
|
||||
pkgNames := make(map[*pkg]string)
|
||||
longPkgNames := make(map[*pkg]bool)
|
||||
pkgs := make(map[string]*PackageContext)
|
||||
pkgNames := make(map[*PackageContext]string)
|
||||
longPkgNames := make(map[*PackageContext]bool)
|
||||
|
||||
processPackage := func(pkg *pkg) {
|
||||
if pkg == nil {
|
||||
processPackage := func(pctx *PackageContext) {
|
||||
if pctx == nil {
|
||||
// This is a built-in rule and has no package.
|
||||
return
|
||||
}
|
||||
if _, ok := pkgNames[pkg]; ok {
|
||||
if _, ok := pkgNames[pctx]; ok {
|
||||
// We've already processed this package.
|
||||
return
|
||||
}
|
||||
|
||||
otherPkg, present := pkgs[pkg.shortName]
|
||||
otherPkg, present := pkgs[pctx.shortName]
|
||||
if present {
|
||||
// Short name collision. Both this package and the one that's
|
||||
// already there need to use their full names. We leave the short
|
||||
// name in pkgNames for now so future collisions still get caught.
|
||||
longPkgNames[pkg] = true
|
||||
longPkgNames[pctx] = true
|
||||
longPkgNames[otherPkg] = true
|
||||
} else {
|
||||
// No collision so far. Tentatively set the package's name to be
|
||||
// its short name.
|
||||
pkgNames[pkg] = pkg.shortName
|
||||
pkgNames[pctx] = pctx.shortName
|
||||
}
|
||||
}
|
||||
|
||||
// We try to give all packages their short name, but when we get collisions
|
||||
// we need to use the full unique package name.
|
||||
for v, _ := range liveGlobals.variables {
|
||||
processPackage(v.pkg())
|
||||
processPackage(v.packageContext())
|
||||
}
|
||||
for p, _ := range liveGlobals.pools {
|
||||
processPackage(p.pkg())
|
||||
processPackage(p.packageContext())
|
||||
}
|
||||
for r, _ := range liveGlobals.rules {
|
||||
processPackage(r.pkg())
|
||||
processPackage(r.packageContext())
|
||||
}
|
||||
|
||||
// Add the packages that had collisions using their full unique names. This
|
||||
// will overwrite any short names that were added in the previous step.
|
||||
for pkg := range longPkgNames {
|
||||
pkgNames[pkg] = pkg.fullName
|
||||
for pctx := range longPkgNames {
|
||||
pkgNames[pctx] = pctx.fullName
|
||||
}
|
||||
|
||||
return pkgNames
|
||||
}
|
||||
|
||||
func (c *Context) checkForVariableReferenceCycles(
|
||||
variables map[Variable]*ninjaString, pkgNames map[*pkg]string) {
|
||||
variables map[Variable]*ninjaString, pkgNames map[*PackageContext]string) {
|
||||
|
||||
visited := make(map[Variable]bool) // variables that were already checked
|
||||
checking := make(map[Variable]bool) // variables actively being checked
|
||||
|
@ -1375,11 +1375,11 @@ func (c *Context) writeBuildDir(nw *ninjaWriter) error {
|
|||
}
|
||||
|
||||
type globalEntity interface {
|
||||
fullName(pkgNames map[*pkg]string) string
|
||||
fullName(pkgNames map[*PackageContext]string) string
|
||||
}
|
||||
|
||||
type globalEntitySorter struct {
|
||||
pkgNames map[*pkg]string
|
||||
pkgNames map[*PackageContext]string
|
||||
entities []globalEntity
|
||||
}
|
||||
|
||||
|
|
|
@ -96,9 +96,9 @@ type ModuleContext interface {
|
|||
OtherModuleName(m Module) string
|
||||
OtherModuleErrorf(m Module, fmt string, args ...interface{})
|
||||
|
||||
Variable(name, value string)
|
||||
Rule(name string, params RuleParams, argNames ...string) Rule
|
||||
Build(params BuildParams)
|
||||
Variable(pctx *PackageContext, name, value string)
|
||||
Rule(pctx *PackageContext, name string, params RuleParams, argNames ...string) Rule
|
||||
Build(pctx *PackageContext, params BuildParams)
|
||||
|
||||
VisitDepsDepthFirst(visit func(Module))
|
||||
VisitDepsDepthFirstIf(pred func(Module) bool, visit func(Module))
|
||||
|
@ -188,9 +188,8 @@ func (m *moduleContext) OtherModuleErrorf(module Module, format string,
|
|||
})
|
||||
}
|
||||
|
||||
func (m *moduleContext) Variable(name, value string) {
|
||||
const skip = 2
|
||||
m.scope.ReparentToCallerPackage(skip)
|
||||
func (m *moduleContext) Variable(pctx *PackageContext, name, value string) {
|
||||
m.scope.ReparentTo(pctx)
|
||||
|
||||
v, err := m.scope.AddLocalVariable(name, value)
|
||||
if err != nil {
|
||||
|
@ -200,11 +199,10 @@ func (m *moduleContext) Variable(name, value string) {
|
|||
m.actionDefs.variables = append(m.actionDefs.variables, v)
|
||||
}
|
||||
|
||||
func (m *moduleContext) Rule(name string, params RuleParams,
|
||||
argNames ...string) Rule {
|
||||
func (m *moduleContext) Rule(pctx *PackageContext, name string,
|
||||
params RuleParams, argNames ...string) Rule {
|
||||
|
||||
const skip = 2
|
||||
m.scope.ReparentToCallerPackage(skip)
|
||||
m.scope.ReparentTo(pctx)
|
||||
|
||||
r, err := m.scope.AddLocalRule(name, ¶ms, argNames...)
|
||||
if err != nil {
|
||||
|
@ -216,9 +214,8 @@ func (m *moduleContext) Rule(name string, params RuleParams,
|
|||
return r
|
||||
}
|
||||
|
||||
func (m *moduleContext) Build(params BuildParams) {
|
||||
const skip = 2
|
||||
m.scope.ReparentToCallerPackage(skip)
|
||||
func (m *moduleContext) Build(pctx *PackageContext, params BuildParams) {
|
||||
m.scope.ReparentTo(pctx)
|
||||
|
||||
def, err := parseBuildParams(m.scope, ¶ms)
|
||||
if err != nil {
|
||||
|
|
|
@ -181,7 +181,7 @@ func parseRuleParams(scope scope, params *RuleParams) (*ruleDef,
|
|||
}
|
||||
|
||||
func (r *ruleDef) WriteTo(nw *ninjaWriter, name string,
|
||||
pkgNames map[*pkg]string) error {
|
||||
pkgNames map[*PackageContext]string) error {
|
||||
|
||||
if r.Comment != "" {
|
||||
err := nw.Comment(r.Comment)
|
||||
|
@ -288,7 +288,7 @@ func parseBuildParams(scope scope, params *BuildParams) (*buildDef,
|
|||
return b, nil
|
||||
}
|
||||
|
||||
func (b *buildDef) WriteTo(nw *ninjaWriter, pkgNames map[*pkg]string) error {
|
||||
func (b *buildDef) WriteTo(nw *ninjaWriter, pkgNames map[*PackageContext]string) error {
|
||||
var (
|
||||
rule = b.Rule.fullName(pkgNames)
|
||||
outputs = valueList(b.Outputs, pkgNames, outputEscaper)
|
||||
|
@ -312,7 +312,7 @@ func (b *buildDef) WriteTo(nw *ninjaWriter, pkgNames map[*pkg]string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func valueList(list []*ninjaString, pkgNames map[*pkg]string,
|
||||
func valueList(list []*ninjaString, pkgNames map[*PackageContext]string,
|
||||
escaper *strings.Replacer) []string {
|
||||
|
||||
result := make([]string, len(list))
|
||||
|
|
|
@ -213,11 +213,11 @@ func parseNinjaStrings(scope scope, strs []string) ([]*ninjaString,
|
|||
return result, nil
|
||||
}
|
||||
|
||||
func (n *ninjaString) Value(pkgNames map[*pkg]string) string {
|
||||
func (n *ninjaString) Value(pkgNames map[*PackageContext]string) string {
|
||||
return n.ValueWithEscaper(pkgNames, defaultEscaper)
|
||||
}
|
||||
|
||||
func (n *ninjaString) ValueWithEscaper(pkgNames map[*pkg]string,
|
||||
func (n *ninjaString) ValueWithEscaper(pkgNames map[*PackageContext]string,
|
||||
escaper *strings.Replacer) string {
|
||||
|
||||
str := escaper.Replace(n.strings[0])
|
||||
|
|
|
@ -8,14 +8,76 @@ import (
|
|||
"strings"
|
||||
)
|
||||
|
||||
type pkg struct {
|
||||
// A PackageContext provides a way to create package-scoped Ninja pools,
|
||||
// rules, and variables. A Go package should create a single unexported
|
||||
// package-scoped PackageContext variable that it uses to create all package-
|
||||
// scoped Ninja object definitions. This PackageContext object should then be
|
||||
// passed to all calls to define module- or singleton-specific Ninja
|
||||
// definitions. For example:
|
||||
//
|
||||
// package blah
|
||||
//
|
||||
// import (
|
||||
// "blueprint"
|
||||
// )
|
||||
//
|
||||
// var (
|
||||
// pctx = NewPackageContext("path/to/blah")
|
||||
//
|
||||
// myPrivateVar = pctx.StaticVariable("myPrivateVar", "abcdef")
|
||||
// MyExportedVar = pctx.StaticVariable("MyExportedVar", "$myPrivateVar 123456!")
|
||||
//
|
||||
// SomeRule = pctx.StaticRule(...)
|
||||
// )
|
||||
//
|
||||
// // ...
|
||||
//
|
||||
// func (m *MyModule) GenerateBuildActions(ctx blueprint.Module) {
|
||||
// ctx.Build(pctx, blueprint.BuildParams{
|
||||
// Rule: SomeRule,
|
||||
// Outputs: []string{"$myPrivateVar"},
|
||||
// })
|
||||
// }
|
||||
type PackageContext struct {
|
||||
fullName string
|
||||
shortName string
|
||||
pkgPath string
|
||||
scope *basicScope
|
||||
}
|
||||
|
||||
var pkgs = map[string]*pkg{}
|
||||
var packageContexts = map[string]*PackageContext{}
|
||||
|
||||
// NewPackageContext creates a PackageContext object for a given package. The
|
||||
// pkgPath argument should always be set to the full path used to import the
|
||||
// package. This function may only be called from a Go package's init()
|
||||
// function or as part of a package-scoped variable initialization.
|
||||
func NewPackageContext(pkgPath string) *PackageContext {
|
||||
checkCalledFromInit()
|
||||
|
||||
if _, present := packageContexts[pkgPath]; present {
|
||||
panic(fmt.Errorf("package %q already has a package context"))
|
||||
}
|
||||
|
||||
pkgName := pkgPathToName(pkgPath)
|
||||
err := validateNinjaName(pkgName)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
i := strings.LastIndex(pkgPath, "/")
|
||||
shortName := pkgPath[i+1:]
|
||||
|
||||
p := &PackageContext{
|
||||
fullName: pkgName,
|
||||
shortName: shortName,
|
||||
pkgPath: pkgPath,
|
||||
scope: newScope(nil),
|
||||
}
|
||||
|
||||
packageContexts[pkgPath] = p
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
var Phony Rule = &builtinRule{
|
||||
name_: "phony",
|
||||
|
@ -24,24 +86,29 @@ var Phony Rule = &builtinRule{
|
|||
var errRuleIsBuiltin = errors.New("the rule is a built-in")
|
||||
var errVariableIsArg = errors.New("argument variables have no value")
|
||||
|
||||
// We make a Ninja-friendly name out of a Go package name by replaceing all the
|
||||
// '/' characters with '.'. We assume the results are unique, though this is
|
||||
// not 100% guaranteed for Go package names that already contain '.' characters.
|
||||
// Disallowing package names with '.' isn't reasonable since many package names
|
||||
// contain the name of the hosting site (e.g. "code.google.com"). In practice
|
||||
// this probably isn't really a problem.
|
||||
func pkgPathToName(pkgPath string) string {
|
||||
return strings.Replace(pkgPath, "/", ".", -1)
|
||||
// checkCalledFromInit panics if a Go package's init function is not on the
|
||||
// call stack.
|
||||
func checkCalledFromInit() {
|
||||
for skip := 3; ; skip++ {
|
||||
_, funcName, ok := callerName(skip)
|
||||
if !ok {
|
||||
panic("not called from an init func")
|
||||
}
|
||||
|
||||
if funcName == "init" || strings.HasPrefix(funcName, "init·") {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// callerName returns the package path and function name of the calling
|
||||
// function. The skip argument has the same meaning as the skip argument of
|
||||
// runtime.Callers.
|
||||
func callerName(skip int) (pkgPath, funcName string) {
|
||||
func callerName(skip int) (pkgPath, funcName string, ok bool) {
|
||||
var pc [1]uintptr
|
||||
n := runtime.Callers(skip+1, pc[:])
|
||||
if n != 1 {
|
||||
panic("unable to get caller pc")
|
||||
return "", "", false
|
||||
}
|
||||
|
||||
f := runtime.FuncForPC(pc[0])
|
||||
|
@ -61,70 +128,46 @@ func callerName(skip int) (pkgPath, funcName string) {
|
|||
|
||||
pkgPath = fullName[:lastDotIndex]
|
||||
funcName = fullName[lastDotIndex+1:]
|
||||
ok = true
|
||||
return
|
||||
}
|
||||
|
||||
// callerPackage returns the pkg of the function that called the caller of
|
||||
// callerPackage. The caller of callerPackage must have been called from an
|
||||
// init function of the package or callerPackage will panic.
|
||||
//
|
||||
// Looking for the package's init function on the call stack and using that to
|
||||
// determine its package name is unfortunately dependent upon Go runtime
|
||||
// implementation details. However, it allows us to ensure that it's easy to
|
||||
// determine where a definition in a .ninja file came from.
|
||||
func callerPackage() *pkg {
|
||||
pkgPath, funcName := callerName(3)
|
||||
|
||||
if funcName != "init" && !strings.HasPrefix(funcName, "init·") {
|
||||
panic("not called from an init func")
|
||||
}
|
||||
|
||||
pkgName := pkgPathToName(pkgPath)
|
||||
err := validateNinjaName(pkgName)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
i := strings.LastIndex(pkgPath, "/")
|
||||
shortName := pkgPath[i+1:]
|
||||
|
||||
p, ok := pkgs[pkgPath]
|
||||
if !ok {
|
||||
p = &pkg{
|
||||
fullName: pkgName,
|
||||
shortName: shortName,
|
||||
pkgPath: pkgPath,
|
||||
scope: newScope(nil),
|
||||
}
|
||||
pkgs[pkgPath] = p
|
||||
}
|
||||
|
||||
return p
|
||||
// pkgPathToName makes a Ninja-friendly name out of a Go package name by
|
||||
// replaceing all the '/' characters with '.'. We assume the results are
|
||||
// unique, though this is not 100% guaranteed for Go package names that
|
||||
// already contain '.' characters. Disallowing package names with '.' isn't
|
||||
// reasonable since many package names contain the name of the hosting site
|
||||
// (e.g. "code.google.com"). In practice this probably isn't really a
|
||||
// problem.
|
||||
func pkgPathToName(pkgPath string) string {
|
||||
return strings.Replace(pkgPath, "/", ".", -1)
|
||||
}
|
||||
|
||||
// Import enables access to the exported Ninja pools, rules, and variables that
|
||||
// are defined at the package scope of another Go package. Go's visibility
|
||||
// rules apply to these references - capitalized names indicate that something
|
||||
// is exported. It may only be called from a Go package's init() function. The
|
||||
// Go package path passed to Import must have already been imported into the Go
|
||||
// package using a Go import statement. The imported variables may then be
|
||||
// accessed from Ninja strings as "${pkg.Variable}", while the imported rules
|
||||
// can simply be accessed as exported Go variables from the package. For
|
||||
// example:
|
||||
// Import enables access to the exported Ninja pools, rules, and variables
|
||||
// that are defined at the package scope of another Go package. Go's
|
||||
// visibility rules apply to these references - capitalized names indicate
|
||||
// that something is exported. It may only be called from a Go package's
|
||||
// init() function. The Go package path passed to Import must have already
|
||||
// been imported into the Go package using a Go import statement. The
|
||||
// imported variables may then be accessed from Ninja strings as
|
||||
// "${pkg.Variable}", while the imported rules can simply be accessed as
|
||||
// exported Go variables from the package. For example:
|
||||
//
|
||||
// import (
|
||||
// "blueprint"
|
||||
// "foo/bar"
|
||||
// )
|
||||
//
|
||||
// var pctx = NewPackagePath("blah")
|
||||
//
|
||||
// func init() {
|
||||
// blueprint.Import("foo/bar")
|
||||
// pctx.Import("foo/bar")
|
||||
// }
|
||||
//
|
||||
// ...
|
||||
//
|
||||
// func (m *MyModule) GenerateBuildActions(ctx blueprint.Module) {
|
||||
// ctx.Build(blueprint.BuildParams{
|
||||
// ctx.Build(pctx, blueprint.BuildParams{
|
||||
// Rule: bar.SomeRule,
|
||||
// Outputs: []string{"${bar.SomeVariable}"},
|
||||
// })
|
||||
|
@ -135,15 +178,14 @@ func callerPackage() *pkg {
|
|||
// from Go's import declaration, which derives the local name from the package
|
||||
// clause in the imported package. By convention these names are made to match,
|
||||
// but this is not required.
|
||||
func Import(pkgPath string) {
|
||||
callerPkg := callerPackage()
|
||||
|
||||
importPkg, ok := pkgs[pkgPath]
|
||||
func (p *PackageContext) Import(pkgPath string) {
|
||||
checkCalledFromInit()
|
||||
importPkg, ok := packageContexts[pkgPath]
|
||||
if !ok {
|
||||
panic(fmt.Errorf("package %q has no Blueprints definitions", pkgPath))
|
||||
panic(fmt.Errorf("package %q has no context", pkgPath))
|
||||
}
|
||||
|
||||
err := callerPkg.scope.AddImport(importPkg.shortName, importPkg.scope)
|
||||
err := p.scope.AddImport(importPkg.shortName, importPkg.scope)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
@ -152,12 +194,11 @@ func Import(pkgPath string) {
|
|||
// ImportAs provides the same functionality as Import, but it allows the local
|
||||
// name that will be used to refer to the package to be specified explicitly.
|
||||
// It may only be called from a Go package's init() function.
|
||||
func ImportAs(as, pkgPath string) {
|
||||
callerPkg := callerPackage()
|
||||
|
||||
importPkg, ok := pkgs[pkgPath]
|
||||
func (p *PackageContext) ImportAs(as, pkgPath string) {
|
||||
checkCalledFromInit()
|
||||
importPkg, ok := packageContexts[pkgPath]
|
||||
if !ok {
|
||||
panic(fmt.Errorf("package %q has no Blueprints definitions", pkgPath))
|
||||
panic(fmt.Errorf("package %q has no context", pkgPath))
|
||||
}
|
||||
|
||||
err := validateNinjaName(as)
|
||||
|
@ -165,14 +206,14 @@ func ImportAs(as, pkgPath string) {
|
|||
panic(err)
|
||||
}
|
||||
|
||||
err = callerPkg.scope.AddImport(as, importPkg.scope)
|
||||
err = p.scope.AddImport(as, importPkg.scope)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
type staticVariable struct {
|
||||
pkg_ *pkg
|
||||
pctx *PackageContext
|
||||
name_ string
|
||||
value_ string
|
||||
}
|
||||
|
@ -186,16 +227,15 @@ type staticVariable struct {
|
|||
// represents a Ninja variable that will be output. The name argument should
|
||||
// exactly match the Go variable name, and the value string may reference other
|
||||
// Ninja variables that are visible within the calling Go package.
|
||||
func StaticVariable(name, value string) Variable {
|
||||
func (p *PackageContext) StaticVariable(name, value string) Variable {
|
||||
checkCalledFromInit()
|
||||
err := validateNinjaName(name)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
pkg := callerPackage()
|
||||
|
||||
v := &staticVariable{pkg, name, value}
|
||||
err = pkg.scope.AddVariable(v)
|
||||
v := &staticVariable{p, name, value}
|
||||
err = p.scope.AddVariable(v)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
@ -203,20 +243,20 @@ func StaticVariable(name, value string) Variable {
|
|||
return v
|
||||
}
|
||||
|
||||
func (v *staticVariable) pkg() *pkg {
|
||||
return v.pkg_
|
||||
func (v *staticVariable) packageContext() *PackageContext {
|
||||
return v.pctx
|
||||
}
|
||||
|
||||
func (v *staticVariable) name() string {
|
||||
return v.name_
|
||||
}
|
||||
|
||||
func (v *staticVariable) fullName(pkgNames map[*pkg]string) string {
|
||||
return packageNamespacePrefix(pkgNames[v.pkg_]) + v.name_
|
||||
func (v *staticVariable) fullName(pkgNames map[*PackageContext]string) string {
|
||||
return packageNamespacePrefix(pkgNames[v.pctx]) + v.name_
|
||||
}
|
||||
|
||||
func (v *staticVariable) value(interface{}) (*ninjaString, error) {
|
||||
ninjaStr, err := parseNinjaString(v.pkg_.scope, v.value_)
|
||||
ninjaStr, err := parseNinjaString(v.pctx.scope, v.value_)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("error parsing variable %s value: %s", v, err)
|
||||
panic(err)
|
||||
|
@ -225,11 +265,11 @@ func (v *staticVariable) value(interface{}) (*ninjaString, error) {
|
|||
}
|
||||
|
||||
func (v *staticVariable) String() string {
|
||||
return v.pkg_.pkgPath + "." + v.name_
|
||||
return v.pctx.pkgPath + "." + v.name_
|
||||
}
|
||||
|
||||
type variableFunc struct {
|
||||
pkg_ *pkg
|
||||
pctx *PackageContext
|
||||
name_ string
|
||||
value_ func(interface{}) (string, error)
|
||||
}
|
||||
|
@ -245,18 +285,18 @@ type variableFunc struct {
|
|||
// exactly match the Go variable name, and the value string returned by f may
|
||||
// reference other Ninja variables that are visible within the calling Go
|
||||
// package.
|
||||
func VariableFunc(name string, f func(config interface{}) (string,
|
||||
error)) Variable {
|
||||
func (p *PackageContext) VariableFunc(name string,
|
||||
f func(config interface{}) (string, error)) Variable {
|
||||
|
||||
checkCalledFromInit()
|
||||
|
||||
err := validateNinjaName(name)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
pkg := callerPackage()
|
||||
|
||||
v := &variableFunc{pkg, name, f}
|
||||
err = pkg.scope.AddVariable(v)
|
||||
v := &variableFunc{p, name, f}
|
||||
err = p.scope.AddVariable(v)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
@ -275,14 +315,16 @@ func VariableFunc(name string, f func(config interface{}) (string,
|
|||
// exactly match the Go variable name, and the value string returned by method
|
||||
// may reference other Ninja variables that are visible within the calling Go
|
||||
// package.
|
||||
func VariableConfigMethod(name string, method interface{}) Variable {
|
||||
func (p *PackageContext) VariableConfigMethod(name string,
|
||||
method interface{}) Variable {
|
||||
|
||||
checkCalledFromInit()
|
||||
|
||||
err := validateNinjaName(name)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
pkg := callerPackage()
|
||||
|
||||
methodValue := reflect.ValueOf(method)
|
||||
validateVariableMethod(name, methodValue)
|
||||
|
||||
|
@ -292,8 +334,8 @@ func VariableConfigMethod(name string, method interface{}) Variable {
|
|||
return resultStr, nil
|
||||
}
|
||||
|
||||
v := &variableFunc{pkg, name, fun}
|
||||
err = pkg.scope.AddVariable(v)
|
||||
v := &variableFunc{p, name, fun}
|
||||
err = p.scope.AddVariable(v)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
@ -301,16 +343,16 @@ func VariableConfigMethod(name string, method interface{}) Variable {
|
|||
return v
|
||||
}
|
||||
|
||||
func (v *variableFunc) pkg() *pkg {
|
||||
return v.pkg_
|
||||
func (v *variableFunc) packageContext() *PackageContext {
|
||||
return v.pctx
|
||||
}
|
||||
|
||||
func (v *variableFunc) name() string {
|
||||
return v.name_
|
||||
}
|
||||
|
||||
func (v *variableFunc) fullName(pkgNames map[*pkg]string) string {
|
||||
return packageNamespacePrefix(pkgNames[v.pkg_]) + v.name_
|
||||
func (v *variableFunc) fullName(pkgNames map[*PackageContext]string) string {
|
||||
return packageNamespacePrefix(pkgNames[v.pctx]) + v.name_
|
||||
}
|
||||
|
||||
func (v *variableFunc) value(config interface{}) (*ninjaString, error) {
|
||||
|
@ -319,7 +361,7 @@ func (v *variableFunc) value(config interface{}) (*ninjaString, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
ninjaStr, err := parseNinjaString(v.pkg_.scope, value)
|
||||
ninjaStr, err := parseNinjaString(v.pctx.scope, value)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("error parsing variable %s value: %s", v, err)
|
||||
panic(err)
|
||||
|
@ -329,7 +371,7 @@ func (v *variableFunc) value(config interface{}) (*ninjaString, error) {
|
|||
}
|
||||
|
||||
func (v *variableFunc) String() string {
|
||||
return v.pkg_.pkgPath + "." + v.name_
|
||||
return v.pctx.pkgPath + "." + v.name_
|
||||
}
|
||||
|
||||
func validateVariableMethod(name string, methodValue reflect.Value) {
|
||||
|
@ -361,7 +403,7 @@ type argVariable struct {
|
|||
name_ string
|
||||
}
|
||||
|
||||
func (v *argVariable) pkg() *pkg {
|
||||
func (v *argVariable) packageContext() *PackageContext {
|
||||
panic("this should not be called")
|
||||
}
|
||||
|
||||
|
@ -369,7 +411,7 @@ func (v *argVariable) name() string {
|
|||
return v.name_
|
||||
}
|
||||
|
||||
func (v *argVariable) fullName(pkgNames map[*pkg]string) string {
|
||||
func (v *argVariable) fullName(pkgNames map[*PackageContext]string) string {
|
||||
return v.name_
|
||||
}
|
||||
|
||||
|
@ -382,7 +424,7 @@ func (v *argVariable) String() string {
|
|||
}
|
||||
|
||||
type staticPool struct {
|
||||
pkg_ *pkg
|
||||
pctx *PackageContext
|
||||
name_ string
|
||||
params PoolParams
|
||||
}
|
||||
|
@ -396,37 +438,37 @@ type staticPool struct {
|
|||
// represents a Ninja pool that will be output. The name argument should
|
||||
// exactly match the Go variable name, and the params fields may reference other
|
||||
// Ninja variables that are visible within the calling Go package.
|
||||
func StaticPool(name string, params PoolParams) Pool {
|
||||
func (p *PackageContext) StaticPool(name string, params PoolParams) Pool {
|
||||
checkCalledFromInit()
|
||||
|
||||
err := validateNinjaName(name)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
pkg := callerPackage()
|
||||
|
||||
p := &staticPool{pkg, name, params}
|
||||
err = pkg.scope.AddPool(p)
|
||||
pool := &staticPool{p, name, params}
|
||||
err = p.scope.AddPool(pool)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return p
|
||||
return pool
|
||||
}
|
||||
|
||||
func (p *staticPool) pkg() *pkg {
|
||||
return p.pkg_
|
||||
func (p *staticPool) packageContext() *PackageContext {
|
||||
return p.pctx
|
||||
}
|
||||
|
||||
func (p *staticPool) name() string {
|
||||
return p.name_
|
||||
}
|
||||
|
||||
func (p *staticPool) fullName(pkgNames map[*pkg]string) string {
|
||||
return packageNamespacePrefix(pkgNames[p.pkg_]) + p.name_
|
||||
func (p *staticPool) fullName(pkgNames map[*PackageContext]string) string {
|
||||
return packageNamespacePrefix(pkgNames[p.pctx]) + p.name_
|
||||
}
|
||||
|
||||
func (p *staticPool) def(config interface{}) (*poolDef, error) {
|
||||
def, err := parsePoolParams(p.pkg_.scope, &p.params)
|
||||
def, err := parsePoolParams(p.pctx.scope, &p.params)
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("error parsing PoolParams for %s: %s", p, err))
|
||||
}
|
||||
|
@ -434,11 +476,11 @@ func (p *staticPool) def(config interface{}) (*poolDef, error) {
|
|||
}
|
||||
|
||||
func (p *staticPool) String() string {
|
||||
return p.pkg_.pkgPath + "." + p.name_
|
||||
return p.pctx.pkgPath + "." + p.name_
|
||||
}
|
||||
|
||||
type poolFunc struct {
|
||||
pkg_ *pkg
|
||||
pctx *PackageContext
|
||||
name_ string
|
||||
paramsFunc func(interface{}) (PoolParams, error)
|
||||
}
|
||||
|
@ -453,33 +495,35 @@ type poolFunc struct {
|
|||
// exactly match the Go variable name, and the string fields of the PoolParams
|
||||
// returned by f may reference other Ninja variables that are visible within the
|
||||
// calling Go package.
|
||||
func PoolFunc(name string, f func(interface{}) (PoolParams, error)) Pool {
|
||||
func (p *PackageContext) PoolFunc(name string, f func(interface{}) (PoolParams,
|
||||
error)) Pool {
|
||||
|
||||
checkCalledFromInit()
|
||||
|
||||
err := validateNinjaName(name)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
pkg := callerPackage()
|
||||
|
||||
p := &poolFunc{pkg, name, f}
|
||||
err = pkg.scope.AddPool(p)
|
||||
pool := &poolFunc{p, name, f}
|
||||
err = p.scope.AddPool(pool)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return p
|
||||
return pool
|
||||
}
|
||||
|
||||
func (p *poolFunc) pkg() *pkg {
|
||||
return p.pkg_
|
||||
func (p *poolFunc) packageContext() *PackageContext {
|
||||
return p.pctx
|
||||
}
|
||||
|
||||
func (p *poolFunc) name() string {
|
||||
return p.name_
|
||||
}
|
||||
|
||||
func (p *poolFunc) fullName(pkgNames map[*pkg]string) string {
|
||||
return packageNamespacePrefix(pkgNames[p.pkg_]) + p.name_
|
||||
func (p *poolFunc) fullName(pkgNames map[*PackageContext]string) string {
|
||||
return packageNamespacePrefix(pkgNames[p.pctx]) + p.name_
|
||||
}
|
||||
|
||||
func (p *poolFunc) def(config interface{}) (*poolDef, error) {
|
||||
|
@ -487,7 +531,7 @@ func (p *poolFunc) def(config interface{}) (*poolDef, error) {
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
def, err := parsePoolParams(p.pkg_.scope, ¶ms)
|
||||
def, err := parsePoolParams(p.pctx.scope, ¶ms)
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("error parsing PoolParams for %s: %s", p, err))
|
||||
}
|
||||
|
@ -495,11 +539,11 @@ func (p *poolFunc) def(config interface{}) (*poolDef, error) {
|
|||
}
|
||||
|
||||
func (p *poolFunc) String() string {
|
||||
return p.pkg_.pkgPath + "." + p.name_
|
||||
return p.pctx.pkgPath + "." + p.name_
|
||||
}
|
||||
|
||||
type staticRule struct {
|
||||
pkg_ *pkg
|
||||
pctx *PackageContext
|
||||
name_ string
|
||||
params RuleParams
|
||||
argNames map[string]bool
|
||||
|
@ -524,8 +568,10 @@ type staticRule struct {
|
|||
// results in the package-scoped variable's value being used for build
|
||||
// statements that do not override the argument. For argument names that do not
|
||||
// shadow package-scoped variables the default value is an empty string.
|
||||
func StaticRule(name string, params RuleParams, argNames ...string) Rule {
|
||||
pkg := callerPackage()
|
||||
func (p *PackageContext) StaticRule(name string, params RuleParams,
|
||||
argNames ...string) Rule {
|
||||
|
||||
checkCalledFromInit()
|
||||
|
||||
err := validateNinjaName(name)
|
||||
if err != nil {
|
||||
|
@ -544,8 +590,8 @@ func StaticRule(name string, params RuleParams, argNames ...string) Rule {
|
|||
|
||||
ruleScope := (*basicScope)(nil) // This will get created lazily
|
||||
|
||||
r := &staticRule{pkg, name, params, argNamesSet, ruleScope}
|
||||
err = pkg.scope.AddRule(r)
|
||||
r := &staticRule{p, name, params, argNamesSet, ruleScope}
|
||||
err = p.scope.AddRule(r)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
@ -553,16 +599,16 @@ func StaticRule(name string, params RuleParams, argNames ...string) Rule {
|
|||
return r
|
||||
}
|
||||
|
||||
func (r *staticRule) pkg() *pkg {
|
||||
return r.pkg_
|
||||
func (r *staticRule) packageContext() *PackageContext {
|
||||
return r.pctx
|
||||
}
|
||||
|
||||
func (r *staticRule) name() string {
|
||||
return r.name_
|
||||
}
|
||||
|
||||
func (r *staticRule) fullName(pkgNames map[*pkg]string) string {
|
||||
return packageNamespacePrefix(pkgNames[r.pkg_]) + r.name_
|
||||
func (r *staticRule) fullName(pkgNames map[*PackageContext]string) string {
|
||||
return packageNamespacePrefix(pkgNames[r.pctx]) + r.name_
|
||||
}
|
||||
|
||||
func (r *staticRule) def(interface{}) (*ruleDef, error) {
|
||||
|
@ -578,7 +624,7 @@ func (r *staticRule) scope() *basicScope {
|
|||
// declared before the args are created. Otherwise we could incorrectly
|
||||
// shadow a package-scoped variable with an arg variable.
|
||||
if r.scope_ == nil {
|
||||
r.scope_ = makeRuleScope(r.pkg_.scope, r.argNames)
|
||||
r.scope_ = makeRuleScope(r.pctx.scope, r.argNames)
|
||||
}
|
||||
return r.scope_
|
||||
}
|
||||
|
@ -588,11 +634,11 @@ func (r *staticRule) isArg(argName string) bool {
|
|||
}
|
||||
|
||||
func (r *staticRule) String() string {
|
||||
return r.pkg_.pkgPath + "." + r.name_
|
||||
return r.pctx.pkgPath + "." + r.name_
|
||||
}
|
||||
|
||||
type ruleFunc struct {
|
||||
pkg_ *pkg
|
||||
pctx *PackageContext
|
||||
name_ string
|
||||
paramsFunc func(interface{}) (RuleParams, error)
|
||||
argNames map[string]bool
|
||||
|
@ -618,10 +664,10 @@ type ruleFunc struct {
|
|||
// scoped variable results in the package-scoped variable's value being used for
|
||||
// build statements that do not override the argument. For argument names that
|
||||
// do not shadow package-scoped variables the default value is an empty string.
|
||||
func RuleFunc(name string, f func(interface{}) (RuleParams, error),
|
||||
argNames ...string) Rule {
|
||||
func (p *PackageContext) RuleFunc(name string, f func(interface{}) (RuleParams,
|
||||
error), argNames ...string) Rule {
|
||||
|
||||
pkg := callerPackage()
|
||||
checkCalledFromInit()
|
||||
|
||||
err := validateNinjaName(name)
|
||||
if err != nil {
|
||||
|
@ -640,25 +686,25 @@ func RuleFunc(name string, f func(interface{}) (RuleParams, error),
|
|||
|
||||
ruleScope := (*basicScope)(nil) // This will get created lazily
|
||||
|
||||
r := &ruleFunc{pkg, name, f, argNamesSet, ruleScope}
|
||||
err = pkg.scope.AddRule(r)
|
||||
rule := &ruleFunc{p, name, f, argNamesSet, ruleScope}
|
||||
err = p.scope.AddRule(rule)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return r
|
||||
return rule
|
||||
}
|
||||
|
||||
func (r *ruleFunc) pkg() *pkg {
|
||||
return r.pkg_
|
||||
func (r *ruleFunc) packageContext() *PackageContext {
|
||||
return r.pctx
|
||||
}
|
||||
|
||||
func (r *ruleFunc) name() string {
|
||||
return r.name_
|
||||
}
|
||||
|
||||
func (r *ruleFunc) fullName(pkgNames map[*pkg]string) string {
|
||||
return packageNamespacePrefix(pkgNames[r.pkg_]) + r.name_
|
||||
func (r *ruleFunc) fullName(pkgNames map[*PackageContext]string) string {
|
||||
return packageNamespacePrefix(pkgNames[r.pctx]) + r.name_
|
||||
}
|
||||
|
||||
func (r *ruleFunc) def(config interface{}) (*ruleDef, error) {
|
||||
|
@ -678,7 +724,7 @@ func (r *ruleFunc) scope() *basicScope {
|
|||
// before the args are created. Otherwise we could incorrectly shadow a
|
||||
// global variable with an arg variable.
|
||||
if r.scope_ == nil {
|
||||
r.scope_ = makeRuleScope(r.pkg_.scope, r.argNames)
|
||||
r.scope_ = makeRuleScope(r.pctx.scope, r.argNames)
|
||||
}
|
||||
return r.scope_
|
||||
}
|
||||
|
@ -688,7 +734,7 @@ func (r *ruleFunc) isArg(argName string) bool {
|
|||
}
|
||||
|
||||
func (r *ruleFunc) String() string {
|
||||
return r.pkg_.pkgPath + "." + r.name_
|
||||
return r.pctx.pkgPath + "." + r.name_
|
||||
}
|
||||
|
||||
type builtinRule struct {
|
||||
|
@ -696,7 +742,7 @@ type builtinRule struct {
|
|||
scope_ *basicScope
|
||||
}
|
||||
|
||||
func (r *builtinRule) pkg() *pkg {
|
||||
func (r *builtinRule) packageContext() *PackageContext {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -704,7 +750,7 @@ func (r *builtinRule) name() string {
|
|||
return r.name_
|
||||
}
|
||||
|
||||
func (r *builtinRule) fullName(pkgNames map[*pkg]string) string {
|
||||
func (r *builtinRule) fullName(pkgNames map[*PackageContext]string) string {
|
||||
return r.name_
|
||||
}
|
||||
|
|
@ -11,9 +11,9 @@ import (
|
|||
// to the output .ninja file. A variable may contain references to other global
|
||||
// Ninja variables, but circular variable references are not allowed.
|
||||
type Variable interface {
|
||||
pkg() *pkg
|
||||
name() string // "foo"
|
||||
fullName(pkgNames map[*pkg]string) string // "pkg.foo" or "path.to.pkg.foo"
|
||||
packageContext() *PackageContext
|
||||
name() string // "foo"
|
||||
fullName(pkgNames map[*PackageContext]string) string // "pkg.foo" or "path.to.pkg.foo"
|
||||
value(config interface{}) (*ninjaString, error)
|
||||
String() string
|
||||
}
|
||||
|
@ -21,9 +21,9 @@ type Variable interface {
|
|||
// A Pool represents a Ninja pool that will be written to the output .ninja
|
||||
// file.
|
||||
type Pool interface {
|
||||
pkg() *pkg
|
||||
name() string // "foo"
|
||||
fullName(pkgNames map[*pkg]string) string // "pkg.foo" or "path.to.pkg.foo"
|
||||
packageContext() *PackageContext
|
||||
name() string // "foo"
|
||||
fullName(pkgNames map[*PackageContext]string) string // "pkg.foo" or "path.to.pkg.foo"
|
||||
def(config interface{}) (*poolDef, error)
|
||||
String() string
|
||||
}
|
||||
|
@ -31,9 +31,9 @@ type Pool interface {
|
|||
// A Rule represents a Ninja build rule that will be written to the output
|
||||
// .ninja file.
|
||||
type Rule interface {
|
||||
pkg() *pkg
|
||||
name() string // "foo"
|
||||
fullName(pkgNames map[*pkg]string) string // "pkg.foo" or "path.to.pkg.foo"
|
||||
packageContext() *PackageContext
|
||||
name() string // "foo"
|
||||
fullName(pkgNames map[*PackageContext]string) string // "pkg.foo" or "path.to.pkg.foo"
|
||||
def(config interface{}) (*ruleDef, error)
|
||||
scope() *basicScope
|
||||
isArg(argName string) bool
|
||||
|
@ -237,26 +237,12 @@ func newLocalScope(parent *basicScope, namePrefix string) *localScope {
|
|||
}
|
||||
}
|
||||
|
||||
// ReparentToCallerPackage sets the localScope's parent scope to the scope of
|
||||
// the Go package of the caller. This allows a ModuleContext and
|
||||
// SingletonContext to be passed to a function defined in a different Go package
|
||||
// with that function having access to all of the package-scoped variables of
|
||||
// its own package.
|
||||
//
|
||||
// The skip argument has the same meaning as the skip argument of
|
||||
// runtime.Callers.
|
||||
func (s *localScope) ReparentToCallerPackage(skip int) {
|
||||
var pkgScope *basicScope
|
||||
|
||||
pkgPath, _ := callerName(skip + 1)
|
||||
pkg, ok := pkgs[pkgPath]
|
||||
if ok {
|
||||
pkgScope = pkg.scope
|
||||
} else {
|
||||
pkgScope = newScope(nil)
|
||||
}
|
||||
|
||||
s.scope.parent = pkgScope
|
||||
// ReparentTo sets the localScope's parent scope to the scope of the given
|
||||
// package context. This allows a ModuleContext and SingletonContext to call
|
||||
// a function defined in a different Go package and have that function retain
|
||||
// access to all of the package-scoped variables of its own package.
|
||||
func (s *localScope) ReparentTo(pctx *PackageContext) {
|
||||
s.scope.parent = pctx.scope
|
||||
}
|
||||
|
||||
func (s *localScope) LookupVariable(name string) (Variable, error) {
|
||||
|
@ -349,7 +335,7 @@ type localVariable struct {
|
|||
value_ *ninjaString
|
||||
}
|
||||
|
||||
func (l *localVariable) pkg() *pkg {
|
||||
func (l *localVariable) packageContext() *PackageContext {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -357,7 +343,7 @@ func (l *localVariable) name() string {
|
|||
return l.name_
|
||||
}
|
||||
|
||||
func (l *localVariable) fullName(pkgNames map[*pkg]string) string {
|
||||
func (l *localVariable) fullName(pkgNames map[*PackageContext]string) string {
|
||||
return l.namePrefix + l.name_
|
||||
}
|
||||
|
||||
|
@ -377,7 +363,7 @@ type localRule struct {
|
|||
scope_ *basicScope
|
||||
}
|
||||
|
||||
func (l *localRule) pkg() *pkg {
|
||||
func (l *localRule) packageContext() *PackageContext {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -385,7 +371,7 @@ func (l *localRule) name() string {
|
|||
return l.name_
|
||||
}
|
||||
|
||||
func (l *localRule) fullName(pkgNames map[*pkg]string) string {
|
||||
func (l *localRule) fullName(pkgNames map[*PackageContext]string) string {
|
||||
return l.namePrefix + l.name_
|
||||
}
|
||||
|
||||
|
|
|
@ -19,16 +19,16 @@ type SingletonContext interface {
|
|||
ModuleErrorf(module Module, format string, args ...interface{})
|
||||
Errorf(format string, args ...interface{})
|
||||
|
||||
Variable(name, value string)
|
||||
Rule(name string, params RuleParams, argNames ...string) Rule
|
||||
Build(params BuildParams)
|
||||
Variable(pctx *PackageContext, name, value string)
|
||||
Rule(pctx *PackageContext, name string, params RuleParams, argNames ...string) Rule
|
||||
Build(pctx *PackageContext, params BuildParams)
|
||||
RequireNinjaVersion(major, minor, micro int)
|
||||
|
||||
// SetBuildDir sets the value of the top-level "builddir" Ninja variable
|
||||
// that controls where Ninja stores its build log files. This value can be
|
||||
// set at most one time for a single build. Setting it multiple times (even
|
||||
// across different singletons) will result in a panic.
|
||||
SetBuildDir(value string)
|
||||
SetBuildDir(pctx *PackageContext, value string)
|
||||
|
||||
VisitAllModules(visit func(Module))
|
||||
VisitAllModulesIf(pred func(Module) bool, visit func(Module))
|
||||
|
@ -86,9 +86,8 @@ func (s *singletonContext) Errorf(format string, args ...interface{}) {
|
|||
s.errs = append(s.errs, fmt.Errorf(format, args...))
|
||||
}
|
||||
|
||||
func (s *singletonContext) Variable(name, value string) {
|
||||
const skip = 2
|
||||
s.scope.ReparentToCallerPackage(skip)
|
||||
func (s *singletonContext) Variable(pctx *PackageContext, name, value string) {
|
||||
s.scope.ReparentTo(pctx)
|
||||
|
||||
v, err := s.scope.AddLocalVariable(name, value)
|
||||
if err != nil {
|
||||
|
@ -98,11 +97,10 @@ func (s *singletonContext) Variable(name, value string) {
|
|||
s.actionDefs.variables = append(s.actionDefs.variables, v)
|
||||
}
|
||||
|
||||
func (s *singletonContext) Rule(name string, params RuleParams,
|
||||
argNames ...string) Rule {
|
||||
func (s *singletonContext) Rule(pctx *PackageContext, name string,
|
||||
params RuleParams, argNames ...string) Rule {
|
||||
|
||||
const skip = 2
|
||||
s.scope.ReparentToCallerPackage(skip)
|
||||
s.scope.ReparentTo(pctx)
|
||||
|
||||
r, err := s.scope.AddLocalRule(name, ¶ms, argNames...)
|
||||
if err != nil {
|
||||
|
@ -114,9 +112,8 @@ func (s *singletonContext) Rule(name string, params RuleParams,
|
|||
return r
|
||||
}
|
||||
|
||||
func (s *singletonContext) Build(params BuildParams) {
|
||||
const skip = 2
|
||||
s.scope.ReparentToCallerPackage(skip)
|
||||
func (s *singletonContext) Build(pctx *PackageContext, params BuildParams) {
|
||||
s.scope.ReparentTo(pctx)
|
||||
|
||||
def, err := parseBuildParams(s.scope, ¶ms)
|
||||
if err != nil {
|
||||
|
@ -130,9 +127,8 @@ func (s *singletonContext) RequireNinjaVersion(major, minor, micro int) {
|
|||
s.context.requireNinjaVersion(major, minor, micro)
|
||||
}
|
||||
|
||||
func (s *singletonContext) SetBuildDir(value string) {
|
||||
const skip = 2
|
||||
s.scope.ReparentToCallerPackage(skip)
|
||||
func (s *singletonContext) SetBuildDir(pctx *PackageContext, value string) {
|
||||
s.scope.ReparentTo(pctx)
|
||||
|
||||
ninjaValue, err := parseNinjaString(s.scope, value)
|
||||
if err != nil {
|
||||
|
|
|
@ -62,13 +62,13 @@ rule g.bootstrap.pack
|
|||
|
||||
build .bootstrap/blueprint/obj/_go_.${g.bootstrap.GoChar}: g.bootstrap.gc $
|
||||
${g.bootstrap.SrcDir}/blueprint/context.go $
|
||||
${g.bootstrap.SrcDir}/blueprint/globals.go $
|
||||
${g.bootstrap.SrcDir}/blueprint/live_tracker.go $
|
||||
${g.bootstrap.SrcDir}/blueprint/mangle.go $
|
||||
${g.bootstrap.SrcDir}/blueprint/module_ctx.go $
|
||||
${g.bootstrap.SrcDir}/blueprint/ninja_defs.go $
|
||||
${g.bootstrap.SrcDir}/blueprint/ninja_strings.go $
|
||||
${g.bootstrap.SrcDir}/blueprint/ninja_writer.go $
|
||||
${g.bootstrap.SrcDir}/blueprint/package_ctx.go $
|
||||
${g.bootstrap.SrcDir}/blueprint/scope.go $
|
||||
${g.bootstrap.SrcDir}/blueprint/singleton_ctx.go $
|
||||
${g.bootstrap.SrcDir}/blueprint/unpack.go | $
|
||||
|
|
Loading…
Reference in a new issue