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