• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright 2014 Google Inc. All rights reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package blueprint
16
17import (
18	"errors"
19	"fmt"
20	"reflect"
21	"regexp"
22	"runtime"
23	"strings"
24	"sync"
25)
26
27// A PackageContext provides a way to create package-scoped Ninja pools,
28// rules, and variables.  A Go package should create a single unexported
29// package-scoped PackageContext variable that it uses to create all package-
30// scoped Ninja object definitions.  This PackageContext object should then be
31// passed to all calls to define module- or singleton-specific Ninja
32// definitions.  For example:
33//
34//     package blah
35//
36//     import (
37//         "blueprint"
38//     )
39//
40//     var (
41//         pctx = NewPackageContext("path/to/blah")
42//
43//         myPrivateVar = pctx.StaticVariable("myPrivateVar", "abcdef")
44//         MyExportedVar = pctx.StaticVariable("MyExportedVar", "$myPrivateVar 123456!")
45//
46//         SomeRule = pctx.StaticRule(...)
47//     )
48//
49//     // ...
50//
51//     func (m *MyModule) GenerateBuildActions(ctx blueprint.Module) {
52//         ctx.Build(pctx, blueprint.BuildParams{
53//             Rule:    SomeRule,
54//             Outputs: []string{"$myPrivateVar"},
55//         })
56//     }
57type PackageContext interface {
58	Import(pkgPath string)
59	ImportAs(as, pkgPath string)
60
61	StaticVariable(name, value string) Variable
62	VariableFunc(name string, f func(config interface{}) (string, error)) Variable
63	VariableConfigMethod(name string, method interface{}) Variable
64
65	StaticPool(name string, params PoolParams) Pool
66	PoolFunc(name string, f func(interface{}) (PoolParams, error)) Pool
67
68	StaticRule(name string, params RuleParams, argNames ...string) Rule
69	RuleFunc(name string, f func(interface{}) (RuleParams, error), argNames ...string) Rule
70
71	AddNinjaFileDeps(deps ...string)
72
73	getScope() *basicScope
74}
75
76type packageContext struct {
77	fullName      string
78	shortName     string
79	pkgPath       string
80	scope         *basicScope
81	ninjaFileDeps []string
82}
83
84var _ PackageContext = &packageContext{}
85
86func (p *packageContext) getScope() *basicScope {
87	return p.scope
88}
89
90var packageContexts = map[string]*packageContext{}
91
92// NewPackageContext creates a PackageContext object for a given package.  The
93// pkgPath argument should always be set to the full path used to import the
94// package.  This function may only be called from a Go package's init()
95// function or as part of a package-scoped variable initialization.
96func NewPackageContext(pkgPath string) PackageContext {
97	checkCalledFromInit()
98
99	if _, present := packageContexts[pkgPath]; present {
100		panic(fmt.Errorf("package %q already has a package context", pkgPath))
101	}
102
103	pkgName := pkgPathToName(pkgPath)
104	err := validateNinjaName(pkgName)
105	if err != nil {
106		panic(err)
107	}
108
109	i := strings.LastIndex(pkgPath, "/")
110	shortName := pkgPath[i+1:]
111
112	p := &packageContext{
113		fullName:  pkgName,
114		shortName: shortName,
115		pkgPath:   pkgPath,
116		scope:     newScope(nil),
117	}
118
119	packageContexts[pkgPath] = p
120
121	return p
122}
123
124var Phony Rule = NewBuiltinRule("phony")
125
126var Console Pool = NewBuiltinPool("console")
127
128var errRuleIsBuiltin = errors.New("the rule is a built-in")
129var errPoolIsBuiltin = errors.New("the pool is a built-in")
130var errVariableIsArg = errors.New("argument variables have no value")
131
132// checkCalledFromInit panics if a Go package's init function is not on the
133// call stack.
134func checkCalledFromInit() {
135	for skip := 3; ; skip++ {
136		_, funcName, ok := callerName(skip)
137		if !ok {
138			panic("not called from an init func")
139		}
140
141		if funcName == "init" || strings.HasPrefix(funcName, "init·") ||
142			funcName == "init.ializers" || strings.HasPrefix(funcName, "init.") {
143			return
144		}
145	}
146}
147
148// A regex to find a package path within a function name. It finds the shortest string that is
149// followed by '.' and doesn't have any '/'s left.
150var pkgPathRe = regexp.MustCompile(`^(.*?)\.([^/]+)$`)
151
152// callerName returns the package path and function name of the calling
153// function.  The skip argument has the same meaning as the skip argument of
154// runtime.Callers.
155func callerName(skip int) (pkgPath, funcName string, ok bool) {
156	var pc [1]uintptr
157	n := runtime.Callers(skip+1, pc[:])
158	if n != 1 {
159		return "", "", false
160	}
161
162	f := runtime.FuncForPC(pc[0]).Name()
163	s := pkgPathRe.FindStringSubmatch(f)
164	if len(s) < 3 {
165		panic(fmt.Errorf("failed to extract package path and function name from %q", f))
166	}
167
168	return s[1], s[2], true
169}
170
171// pkgPathToName makes a Ninja-friendly name out of a Go package name by
172// replaceing all the '/' characters with '.'.  We assume the results are
173// unique, though this is not 100% guaranteed for Go package names that
174// already contain '.' characters. Disallowing package names with '.' isn't
175// reasonable since many package names contain the name of the hosting site
176// (e.g. "code.google.com").  In practice this probably isn't really a
177// problem.
178func pkgPathToName(pkgPath string) string {
179	return strings.Replace(pkgPath, "/", ".", -1)
180}
181
182// Import enables access to the exported Ninja pools, rules, and variables
183// that are defined at the package scope of another Go package.  Go's
184// visibility rules apply to these references - capitalized names indicate
185// that something is exported.  It may only be called from a Go package's
186// init() function.  The Go package path passed to Import must have already
187// been imported into the Go package using a Go import statement.  The
188// imported variables may then be accessed from Ninja strings as
189// "${pkg.Variable}", while the imported rules can simply be accessed as
190// exported Go variables from the package.  For example:
191//
192//     import (
193//         "blueprint"
194//         "foo/bar"
195//     )
196//
197//     var pctx = NewPackagePath("blah")
198//
199//     func init() {
200//         pctx.Import("foo/bar")
201//     }
202//
203//     ...
204//
205//     func (m *MyModule) GenerateBuildActions(ctx blueprint.Module) {
206//         ctx.Build(pctx, blueprint.BuildParams{
207//             Rule:    bar.SomeRule,
208//             Outputs: []string{"${bar.SomeVariable}"},
209//         })
210//     }
211//
212// Note that the local name used to refer to the package in Ninja variable names
213// is derived from pkgPath by extracting the last path component.  This differs
214// from Go's import declaration, which derives the local name from the package
215// clause in the imported package.  By convention these names are made to match,
216// but this is not required.
217func (p *packageContext) Import(pkgPath string) {
218	checkCalledFromInit()
219	importPkg, ok := packageContexts[pkgPath]
220	if !ok {
221		panic(fmt.Errorf("package %q has no context", pkgPath))
222	}
223
224	err := p.scope.AddImport(importPkg.shortName, importPkg.scope)
225	if err != nil {
226		panic(err)
227	}
228}
229
230// ImportAs provides the same functionality as Import, but it allows the local
231// name that will be used to refer to the package to be specified explicitly.
232// It may only be called from a Go package's init() function.
233func (p *packageContext) ImportAs(as, pkgPath string) {
234	checkCalledFromInit()
235	importPkg, ok := packageContexts[pkgPath]
236	if !ok {
237		panic(fmt.Errorf("package %q has no context", pkgPath))
238	}
239
240	err := validateNinjaName(as)
241	if err != nil {
242		panic(err)
243	}
244
245	err = p.scope.AddImport(as, importPkg.scope)
246	if err != nil {
247		panic(err)
248	}
249}
250
251type staticVariable struct {
252	pctx   *packageContext
253	name_  string
254	value_ string
255}
256
257// StaticVariable returns a Variable whose value does not depend on any
258// configuration information.  It may only be called during a Go package's
259// initialization - either from the init() function or as part of a package-
260// scoped variable's initialization.
261//
262// This function is usually used to initialize a package-scoped Go variable that
263// represents a Ninja variable that will be output.  The name argument should
264// exactly match the Go variable name, and the value string may reference other
265// Ninja variables that are visible within the calling Go package.
266func (p *packageContext) StaticVariable(name, value string) Variable {
267	checkCalledFromInit()
268	err := validateNinjaName(name)
269	if err != nil {
270		panic(err)
271	}
272
273	v := &staticVariable{p, name, value}
274	err = p.scope.AddVariable(v)
275	if err != nil {
276		panic(err)
277	}
278
279	return v
280}
281
282func (v *staticVariable) packageContext() *packageContext {
283	return v.pctx
284}
285
286func (v *staticVariable) name() string {
287	return v.name_
288}
289
290func (v *staticVariable) fullName(pkgNames map[*packageContext]string) string {
291	return packageNamespacePrefix(pkgNames[v.pctx]) + v.name_
292}
293
294func (v *staticVariable) value(interface{}) (*ninjaString, error) {
295	ninjaStr, err := parseNinjaString(v.pctx.scope, v.value_)
296	if err != nil {
297		err = fmt.Errorf("error parsing variable %s value: %s", v, err)
298		panic(err)
299	}
300	return ninjaStr, nil
301}
302
303func (v *staticVariable) String() string {
304	return v.pctx.pkgPath + "." + v.name_
305}
306
307type variableFunc struct {
308	pctx   *packageContext
309	name_  string
310	value_ func(interface{}) (string, error)
311}
312
313// VariableFunc returns a Variable whose value is determined by a function that
314// takes a config object as input and returns either the variable value or an
315// error.  It may only be called during a Go package's initialization - either
316// from the init() function or as part of a package-scoped variable's
317// initialization.
318//
319// This function is usually used to initialize a package-scoped Go variable that
320// represents a Ninja variable that will be output.  The name argument should
321// exactly match the Go variable name, and the value string returned by f may
322// reference other Ninja variables that are visible within the calling Go
323// package.
324func (p *packageContext) VariableFunc(name string,
325	f func(config interface{}) (string, error)) Variable {
326
327	checkCalledFromInit()
328
329	err := validateNinjaName(name)
330	if err != nil {
331		panic(err)
332	}
333
334	v := &variableFunc{p, name, f}
335	err = p.scope.AddVariable(v)
336	if err != nil {
337		panic(err)
338	}
339
340	return v
341}
342
343// VariableConfigMethod returns a Variable whose value is determined by calling
344// a method on the config object.  The method must take no arguments and return
345// a single string that will be the variable's value.  It may only be called
346// during a Go package's initialization - either from the init() function or as
347// part of a package-scoped variable's initialization.
348//
349// This function is usually used to initialize a package-scoped Go variable that
350// represents a Ninja variable that will be output.  The name argument should
351// exactly match the Go variable name, and the value string returned by method
352// may reference other Ninja variables that are visible within the calling Go
353// package.
354func (p *packageContext) VariableConfigMethod(name string,
355	method interface{}) Variable {
356
357	checkCalledFromInit()
358
359	err := validateNinjaName(name)
360	if err != nil {
361		panic(err)
362	}
363
364	methodValue := reflect.ValueOf(method)
365	validateVariableMethod(name, methodValue)
366
367	fun := func(config interface{}) (string, error) {
368		result := methodValue.Call([]reflect.Value{reflect.ValueOf(config)})
369		resultStr := result[0].Interface().(string)
370		return resultStr, nil
371	}
372
373	v := &variableFunc{p, name, fun}
374	err = p.scope.AddVariable(v)
375	if err != nil {
376		panic(err)
377	}
378
379	return v
380}
381
382func (v *variableFunc) packageContext() *packageContext {
383	return v.pctx
384}
385
386func (v *variableFunc) name() string {
387	return v.name_
388}
389
390func (v *variableFunc) fullName(pkgNames map[*packageContext]string) string {
391	return packageNamespacePrefix(pkgNames[v.pctx]) + v.name_
392}
393
394func (v *variableFunc) value(config interface{}) (*ninjaString, error) {
395	value, err := v.value_(config)
396	if err != nil {
397		return nil, err
398	}
399
400	ninjaStr, err := parseNinjaString(v.pctx.scope, value)
401	if err != nil {
402		err = fmt.Errorf("error parsing variable %s value: %s", v, err)
403		panic(err)
404	}
405
406	return ninjaStr, nil
407}
408
409func (v *variableFunc) String() string {
410	return v.pctx.pkgPath + "." + v.name_
411}
412
413func validateVariableMethod(name string, methodValue reflect.Value) {
414	methodType := methodValue.Type()
415	if methodType.Kind() != reflect.Func {
416		panic(fmt.Errorf("method given for variable %s is not a function",
417			name))
418	}
419	if n := methodType.NumIn(); n != 1 {
420		panic(fmt.Errorf("method for variable %s has %d inputs (should be 1)",
421			name, n))
422	}
423	if n := methodType.NumOut(); n != 1 {
424		panic(fmt.Errorf("method for variable %s has %d outputs (should be 1)",
425			name, n))
426	}
427	if kind := methodType.Out(0).Kind(); kind != reflect.String {
428		panic(fmt.Errorf("method for variable %s does not return a string",
429			name))
430	}
431}
432
433// An argVariable is a Variable that exists only when it is set by a build
434// statement to pass a value to the rule being invoked.  It has no value, so it
435// can never be used to create a Ninja assignment statement.  It is inserted
436// into the rule's scope, which is used for name lookups within the rule and
437// when assigning argument values as part of a build statement.
438type argVariable struct {
439	name_ string
440}
441
442func (v *argVariable) packageContext() *packageContext {
443	panic("this should not be called")
444}
445
446func (v *argVariable) name() string {
447	return v.name_
448}
449
450func (v *argVariable) fullName(pkgNames map[*packageContext]string) string {
451	return v.name_
452}
453
454func (v *argVariable) value(config interface{}) (*ninjaString, error) {
455	return nil, errVariableIsArg
456}
457
458func (v *argVariable) String() string {
459	return "<arg>:" + v.name_
460}
461
462type staticPool struct {
463	pctx   *packageContext
464	name_  string
465	params PoolParams
466}
467
468// StaticPool returns a Pool whose value does not depend on any configuration
469// information.  It may only be called during a Go package's initialization -
470// either from the init() function or as part of a package-scoped Go variable's
471// initialization.
472//
473// This function is usually used to initialize a package-scoped Go variable that
474// represents a Ninja pool that will be output.  The name argument should
475// exactly match the Go variable name, and the params fields may reference other
476// Ninja variables that are visible within the calling Go package.
477func (p *packageContext) StaticPool(name string, params PoolParams) Pool {
478	checkCalledFromInit()
479
480	err := validateNinjaName(name)
481	if err != nil {
482		panic(err)
483	}
484
485	pool := &staticPool{p, name, params}
486	err = p.scope.AddPool(pool)
487	if err != nil {
488		panic(err)
489	}
490
491	return pool
492}
493
494func (p *staticPool) packageContext() *packageContext {
495	return p.pctx
496}
497
498func (p *staticPool) name() string {
499	return p.name_
500}
501
502func (p *staticPool) fullName(pkgNames map[*packageContext]string) string {
503	return packageNamespacePrefix(pkgNames[p.pctx]) + p.name_
504}
505
506func (p *staticPool) def(config interface{}) (*poolDef, error) {
507	def, err := parsePoolParams(p.pctx.scope, &p.params)
508	if err != nil {
509		panic(fmt.Errorf("error parsing PoolParams for %s: %s", p, err))
510	}
511	return def, nil
512}
513
514func (p *staticPool) String() string {
515	return p.pctx.pkgPath + "." + p.name_
516}
517
518type poolFunc struct {
519	pctx       *packageContext
520	name_      string
521	paramsFunc func(interface{}) (PoolParams, error)
522}
523
524// PoolFunc returns a Pool whose value is determined by a function that takes a
525// config object as input and returns either the pool parameters or an error. It
526// may only be called during a Go package's initialization - either from the
527// init() function or as part of a package-scoped variable's initialization.
528//
529// This function is usually used to initialize a package-scoped Go variable that
530// represents a Ninja pool that will be output.  The name argument should
531// exactly match the Go variable name, and the string fields of the PoolParams
532// returned by f may reference other Ninja variables that are visible within the
533// calling Go package.
534func (p *packageContext) PoolFunc(name string, f func(interface{}) (PoolParams,
535	error)) Pool {
536
537	checkCalledFromInit()
538
539	err := validateNinjaName(name)
540	if err != nil {
541		panic(err)
542	}
543
544	pool := &poolFunc{p, name, f}
545	err = p.scope.AddPool(pool)
546	if err != nil {
547		panic(err)
548	}
549
550	return pool
551}
552
553func (p *poolFunc) packageContext() *packageContext {
554	return p.pctx
555}
556
557func (p *poolFunc) name() string {
558	return p.name_
559}
560
561func (p *poolFunc) fullName(pkgNames map[*packageContext]string) string {
562	return packageNamespacePrefix(pkgNames[p.pctx]) + p.name_
563}
564
565func (p *poolFunc) def(config interface{}) (*poolDef, error) {
566	params, err := p.paramsFunc(config)
567	if err != nil {
568		return nil, err
569	}
570	def, err := parsePoolParams(p.pctx.scope, &params)
571	if err != nil {
572		panic(fmt.Errorf("error parsing PoolParams for %s: %s", p, err))
573	}
574	return def, nil
575}
576
577func (p *poolFunc) String() string {
578	return p.pctx.pkgPath + "." + p.name_
579}
580
581type builtinPool struct {
582	name_ string
583}
584
585func (p *builtinPool) packageContext() *packageContext {
586	return nil
587}
588
589func (p *builtinPool) name() string {
590	return p.name_
591}
592
593func (p *builtinPool) fullName(pkgNames map[*packageContext]string) string {
594	return p.name_
595}
596
597func (p *builtinPool) def(config interface{}) (*poolDef, error) {
598	return nil, errPoolIsBuiltin
599}
600
601// NewBuiltinPool returns a Pool object that refers to a pool name created outside of Blueprint
602func NewBuiltinPool(name string) Pool {
603	return &builtinPool{
604		name_: name,
605	}
606}
607
608func (p *builtinPool) String() string {
609	return "<builtin>:" + p.name_
610}
611
612type staticRule struct {
613	pctx       *packageContext
614	name_      string
615	params     RuleParams
616	argNames   map[string]bool
617	scope_     *basicScope
618	sync.Mutex // protects scope_ during lazy creation
619}
620
621// StaticRule returns a Rule whose value does not depend on any configuration
622// information.  It may only be called during a Go package's initialization -
623// either from the init() function or as part of a package-scoped Go variable's
624// initialization.
625//
626// This function is usually used to initialize a package-scoped Go variable that
627// represents a Ninja rule that will be output.  The name argument should
628// exactly match the Go variable name, and the params fields may reference other
629// Ninja variables that are visible within the calling Go package.
630//
631// The argNames arguments list Ninja variables that may be overridden by Ninja
632// build statements that invoke the rule.  These arguments may be referenced in
633// any of the string fields of params.  Arguments can shadow package-scoped
634// variables defined within the caller's Go package, but they may not shadow
635// those defined in another package.  Shadowing a package-scoped variable
636// results in the package-scoped variable's value being used for build
637// statements that do not override the argument.  For argument names that do not
638// shadow package-scoped variables the default value is an empty string.
639func (p *packageContext) StaticRule(name string, params RuleParams,
640	argNames ...string) Rule {
641
642	checkCalledFromInit()
643
644	err := validateNinjaName(name)
645	if err != nil {
646		panic(err)
647	}
648
649	err = validateArgNames(argNames)
650	if err != nil {
651		panic(fmt.Errorf("invalid argument name: %s", err))
652	}
653
654	argNamesSet := make(map[string]bool)
655	for _, argName := range argNames {
656		argNamesSet[argName] = true
657	}
658
659	ruleScope := (*basicScope)(nil) // This will get created lazily
660
661	r := &staticRule{
662		pctx:     p,
663		name_:    name,
664		params:   params,
665		argNames: argNamesSet,
666		scope_:   ruleScope,
667	}
668	err = p.scope.AddRule(r)
669	if err != nil {
670		panic(err)
671	}
672
673	return r
674}
675
676func (r *staticRule) packageContext() *packageContext {
677	return r.pctx
678}
679
680func (r *staticRule) name() string {
681	return r.name_
682}
683
684func (r *staticRule) fullName(pkgNames map[*packageContext]string) string {
685	return packageNamespacePrefix(pkgNames[r.pctx]) + r.name_
686}
687
688func (r *staticRule) def(interface{}) (*ruleDef, error) {
689	def, err := parseRuleParams(r.scope(), &r.params)
690	if err != nil {
691		panic(fmt.Errorf("error parsing RuleParams for %s: %s", r, err))
692	}
693	return def, nil
694}
695
696func (r *staticRule) scope() *basicScope {
697	// We lazily create the scope so that all the package-scoped variables get
698	// declared before the args are created.  Otherwise we could incorrectly
699	// shadow a package-scoped variable with an arg variable.
700	r.Lock()
701	defer r.Unlock()
702
703	if r.scope_ == nil {
704		r.scope_ = makeRuleScope(r.pctx.scope, r.argNames)
705	}
706	return r.scope_
707}
708
709func (r *staticRule) isArg(argName string) bool {
710	return r.argNames[argName]
711}
712
713func (r *staticRule) String() string {
714	return r.pctx.pkgPath + "." + r.name_
715}
716
717type ruleFunc struct {
718	pctx       *packageContext
719	name_      string
720	paramsFunc func(interface{}) (RuleParams, error)
721	argNames   map[string]bool
722	scope_     *basicScope
723	sync.Mutex // protects scope_ during lazy creation
724}
725
726// RuleFunc returns a Rule whose value is determined by a function that takes a
727// config object as input and returns either the rule parameters or an error. It
728// may only be called during a Go package's initialization - either from the
729// init() function or as part of a package-scoped variable's initialization.
730//
731// This function is usually used to initialize a package-scoped Go variable that
732// represents a Ninja rule that will be output.  The name argument should
733// exactly match the Go variable name, and the string fields of the RuleParams
734// returned by f may reference other Ninja variables that are visible within the
735// calling Go package.
736//
737// The argNames arguments list Ninja variables that may be overridden by Ninja
738// build statements that invoke the rule.  These arguments may be referenced in
739// any of the string fields of the RuleParams returned by f.  Arguments can
740// shadow package-scoped variables defined within the caller's Go package, but
741// they may not shadow those defined in another package.  Shadowing a package-
742// scoped variable results in the package-scoped variable's value being used for
743// build statements that do not override the argument.  For argument names that
744// do not shadow package-scoped variables the default value is an empty string.
745func (p *packageContext) RuleFunc(name string, f func(interface{}) (RuleParams,
746	error), argNames ...string) Rule {
747
748	checkCalledFromInit()
749
750	err := validateNinjaName(name)
751	if err != nil {
752		panic(err)
753	}
754
755	err = validateArgNames(argNames)
756	if err != nil {
757		panic(fmt.Errorf("invalid argument name: %s", err))
758	}
759
760	argNamesSet := make(map[string]bool)
761	for _, argName := range argNames {
762		argNamesSet[argName] = true
763	}
764
765	ruleScope := (*basicScope)(nil) // This will get created lazily
766
767	rule := &ruleFunc{
768		pctx:       p,
769		name_:      name,
770		paramsFunc: f,
771		argNames:   argNamesSet,
772		scope_:     ruleScope,
773	}
774	err = p.scope.AddRule(rule)
775	if err != nil {
776		panic(err)
777	}
778
779	return rule
780}
781
782func (r *ruleFunc) packageContext() *packageContext {
783	return r.pctx
784}
785
786func (r *ruleFunc) name() string {
787	return r.name_
788}
789
790func (r *ruleFunc) fullName(pkgNames map[*packageContext]string) string {
791	return packageNamespacePrefix(pkgNames[r.pctx]) + r.name_
792}
793
794func (r *ruleFunc) def(config interface{}) (*ruleDef, error) {
795	params, err := r.paramsFunc(config)
796	if err != nil {
797		return nil, err
798	}
799	def, err := parseRuleParams(r.scope(), &params)
800	if err != nil {
801		panic(fmt.Errorf("error parsing RuleParams for %s: %s", r, err))
802	}
803	return def, nil
804}
805
806func (r *ruleFunc) scope() *basicScope {
807	// We lazily create the scope so that all the global variables get declared
808	// before the args are created.  Otherwise we could incorrectly shadow a
809	// global variable with an arg variable.
810	r.Lock()
811	defer r.Unlock()
812
813	if r.scope_ == nil {
814		r.scope_ = makeRuleScope(r.pctx.scope, r.argNames)
815	}
816	return r.scope_
817}
818
819func (r *ruleFunc) isArg(argName string) bool {
820	return r.argNames[argName]
821}
822
823func (r *ruleFunc) String() string {
824	return r.pctx.pkgPath + "." + r.name_
825}
826
827type builtinRule struct {
828	name_      string
829	scope_     *basicScope
830	sync.Mutex // protects scope_ during lazy creation
831}
832
833func (r *builtinRule) packageContext() *packageContext {
834	return nil
835}
836
837func (r *builtinRule) name() string {
838	return r.name_
839}
840
841func (r *builtinRule) fullName(pkgNames map[*packageContext]string) string {
842	return r.name_
843}
844
845func (r *builtinRule) def(config interface{}) (*ruleDef, error) {
846	return nil, errRuleIsBuiltin
847}
848
849func (r *builtinRule) scope() *basicScope {
850	r.Lock()
851	defer r.Unlock()
852
853	if r.scope_ == nil {
854		r.scope_ = makeRuleScope(nil, nil)
855	}
856	return r.scope_
857}
858
859func (r *builtinRule) isArg(argName string) bool {
860	return false
861}
862
863func (r *builtinRule) String() string {
864	return "<builtin>:" + r.name_
865}
866
867// NewBuiltinRule returns a Rule object that refers to a rule that was created outside of Blueprint
868func NewBuiltinRule(name string) Rule {
869	return &builtinRule{
870		name_: name,
871	}
872}
873
874func (p *packageContext) AddNinjaFileDeps(deps ...string) {
875	p.ninjaFileDeps = append(p.ninjaFileDeps, deps...)
876}
877