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