• 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(ctx VariableFuncContext, 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)(nil)
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	fullName_ string
257}
258
259// StaticVariable returns a Variable whose value does not depend on any
260// configuration information.  It may only be called during a Go package's
261// initialization - either from the init() function or as part of a package-
262// scoped variable's initialization.
263//
264// This function is usually used to initialize a package-scoped Go variable that
265// represents a Ninja variable that will be output.  The name argument should
266// exactly match the Go variable name, and the value string may reference other
267// Ninja variables that are visible within the calling Go package.
268func (p *packageContext) StaticVariable(name, value string) Variable {
269	checkCalledFromInit()
270	err := validateNinjaName(name)
271	if err != nil {
272		panic(err)
273	}
274
275	v := &staticVariable{
276		pctx:   p,
277		name_:  name,
278		value_: value,
279	}
280	err = p.scope.AddVariable(v)
281	if err != nil {
282		panic(err)
283	}
284
285	return v
286}
287
288func (v *staticVariable) packageContext() *packageContext {
289	return v.pctx
290}
291
292func (v *staticVariable) name() string {
293	return v.name_
294}
295
296func (v *staticVariable) fullName(pkgNames map[*packageContext]string) string {
297	if v.fullName_ != "" {
298		return v.fullName_
299	}
300	return packageNamespacePrefix(pkgNames[v.pctx]) + v.name_
301}
302
303func (v *staticVariable) memoizeFullName(pkgNames map[*packageContext]string) {
304	v.fullName_ = v.fullName(pkgNames)
305}
306
307func (v *staticVariable) value(VariableFuncContext, interface{}) (ninjaString, error) {
308	ninjaStr, err := parseNinjaString(v.pctx.scope, v.value_)
309	if err != nil {
310		err = fmt.Errorf("error parsing variable %s value: %s", v, err)
311		panic(err)
312	}
313	return ninjaStr, nil
314}
315
316func (v *staticVariable) String() string {
317	return v.pctx.pkgPath + "." + v.name_
318}
319
320type variableFunc struct {
321	pctx      *packageContext
322	name_     string
323	value_    func(VariableFuncContext, interface{}) (string, error)
324	fullName_ string
325}
326
327// VariableFuncContext is passed to VariableFunc functions.
328type VariableFuncContext interface {
329	// GlobWithDeps returns a list of files and directories that match the
330	// specified pattern but do not match any of the patterns in excludes.
331	// Any directories will have a '/' suffix.  It also adds efficient
332	// dependencies to rerun the primary builder whenever a file matching
333	// the pattern as added or removed, without rerunning if a file that
334	// does not match the pattern is added to a searched directory.
335	GlobWithDeps(globPattern string, excludes []string) ([]string, error)
336}
337
338type variableFuncContext struct {
339	context *Context
340}
341
342func (v *variableFuncContext) GlobWithDeps(pattern string,
343	excludes []string) ([]string, error) {
344	return v.context.glob(pattern, excludes)
345}
346
347// VariableFunc returns a Variable whose value is determined by a function that
348// takes a config object as input and returns either the variable value or an
349// error.  It may only be called during a Go package's initialization - either
350// from the init() function or as part of a package-scoped variable's
351// initialization.
352//
353// This function is usually used to initialize a package-scoped Go variable that
354// represents a Ninja variable that will be output.  The name argument should
355// exactly match the Go variable name, and the value string returned by f may
356// reference other Ninja variables that are visible within the calling Go
357// package.
358func (p *packageContext) VariableFunc(name string,
359	f func(ctx VariableFuncContext, config interface{}) (string, error)) Variable {
360
361	checkCalledFromInit()
362
363	err := validateNinjaName(name)
364	if err != nil {
365		panic(err)
366	}
367
368	v := &variableFunc{
369		pctx:   p,
370		name_:  name,
371		value_: f,
372	}
373	err = p.scope.AddVariable(v)
374	if err != nil {
375		panic(err)
376	}
377
378	return v
379}
380
381// VariableConfigMethod returns a Variable whose value is determined by calling
382// a method on the config object.  The method must take no arguments and return
383// a single string that will be the variable's value.  It may only be called
384// during a Go package's initialization - either from the init() function or as
385// part of a package-scoped variable's initialization.
386//
387// This function is usually used to initialize a package-scoped Go variable that
388// represents a Ninja variable that will be output.  The name argument should
389// exactly match the Go variable name, and the value string returned by method
390// may reference other Ninja variables that are visible within the calling Go
391// package.
392func (p *packageContext) VariableConfigMethod(name string,
393	method interface{}) Variable {
394
395	checkCalledFromInit()
396
397	err := validateNinjaName(name)
398	if err != nil {
399		panic(err)
400	}
401
402	methodValue := reflect.ValueOf(method)
403	validateVariableMethod(name, methodValue)
404
405	fun := func(ctx VariableFuncContext, config interface{}) (string, error) {
406		result := methodValue.Call([]reflect.Value{reflect.ValueOf(config)})
407		resultStr := result[0].Interface().(string)
408		return resultStr, nil
409	}
410
411	v := &variableFunc{
412		pctx:   p,
413		name_:  name,
414		value_: fun,
415	}
416	err = p.scope.AddVariable(v)
417	if err != nil {
418		panic(err)
419	}
420
421	return v
422}
423
424func (v *variableFunc) packageContext() *packageContext {
425	return v.pctx
426}
427
428func (v *variableFunc) name() string {
429	return v.name_
430}
431
432func (v *variableFunc) fullName(pkgNames map[*packageContext]string) string {
433	if v.fullName_ != "" {
434		return v.fullName_
435	}
436	return packageNamespacePrefix(pkgNames[v.pctx]) + v.name_
437}
438
439func (v *variableFunc) memoizeFullName(pkgNames map[*packageContext]string) {
440	v.fullName_ = v.fullName(pkgNames)
441}
442
443func (v *variableFunc) value(ctx VariableFuncContext, config interface{}) (ninjaString, error) {
444	value, err := v.value_(ctx, config)
445	if err != nil {
446		return nil, err
447	}
448
449	ninjaStr, err := parseNinjaString(v.pctx.scope, value)
450	if err != nil {
451		err = fmt.Errorf("error parsing variable %s value: %s", v, err)
452		panic(err)
453	}
454
455	return ninjaStr, nil
456}
457
458func (v *variableFunc) String() string {
459	return v.pctx.pkgPath + "." + v.name_
460}
461
462func validateVariableMethod(name string, methodValue reflect.Value) {
463	methodType := methodValue.Type()
464	if methodType.Kind() != reflect.Func {
465		panic(fmt.Errorf("method given for variable %s is not a function",
466			name))
467	}
468	if n := methodType.NumIn(); n != 1 {
469		panic(fmt.Errorf("method for variable %s has %d inputs (should be 1)",
470			name, n))
471	}
472	if n := methodType.NumOut(); n != 1 {
473		panic(fmt.Errorf("method for variable %s has %d outputs (should be 1)",
474			name, n))
475	}
476	if kind := methodType.Out(0).Kind(); kind != reflect.String {
477		panic(fmt.Errorf("method for variable %s does not return a string",
478			name))
479	}
480}
481
482// An argVariable is a Variable that exists only when it is set by a build
483// statement to pass a value to the rule being invoked.  It has no value, so it
484// can never be used to create a Ninja assignment statement.  It is inserted
485// into the rule's scope, which is used for name lookups within the rule and
486// when assigning argument values as part of a build statement.
487type argVariable struct {
488	name_ string
489}
490
491func (v *argVariable) packageContext() *packageContext {
492	panic("this should not be called")
493}
494
495func (v *argVariable) name() string {
496	return v.name_
497}
498
499func (v *argVariable) fullName(pkgNames map[*packageContext]string) string {
500	return v.name_
501}
502
503func (v *argVariable) memoizeFullName(pkgNames map[*packageContext]string) {
504	// Nothing to do, full name is known at initialization.
505}
506
507func (v *argVariable) value(ctx VariableFuncContext, config interface{}) (ninjaString, error) {
508	return nil, errVariableIsArg
509}
510
511func (v *argVariable) String() string {
512	return "<arg>:" + v.name_
513}
514
515type staticPool struct {
516	pctx      *packageContext
517	name_     string
518	params    PoolParams
519	fullName_ string
520}
521
522// StaticPool returns a Pool whose value does not depend on any configuration
523// information.  It may only be called during a Go package's initialization -
524// either from the init() function or as part of a package-scoped Go variable's
525// initialization.
526//
527// This function is usually used to initialize a package-scoped Go variable that
528// represents a Ninja pool that will be output.  The name argument should
529// exactly match the Go variable name, and the params fields may reference other
530// Ninja variables that are visible within the calling Go package.
531func (p *packageContext) StaticPool(name string, params PoolParams) Pool {
532	checkCalledFromInit()
533
534	err := validateNinjaName(name)
535	if err != nil {
536		panic(err)
537	}
538
539	pool := &staticPool{
540		pctx:   p,
541		name_:  name,
542		params: params,
543	}
544	err = p.scope.AddPool(pool)
545	if err != nil {
546		panic(err)
547	}
548
549	return pool
550}
551
552func (p *staticPool) packageContext() *packageContext {
553	return p.pctx
554}
555
556func (p *staticPool) name() string {
557	return p.name_
558}
559
560func (p *staticPool) fullName(pkgNames map[*packageContext]string) string {
561	if p.fullName_ != "" {
562		return p.fullName_
563	}
564	return packageNamespacePrefix(pkgNames[p.pctx]) + p.name_
565}
566
567func (p *staticPool) memoizeFullName(pkgNames map[*packageContext]string) {
568	p.fullName_ = p.fullName(pkgNames)
569}
570
571func (p *staticPool) def(config interface{}) (*poolDef, error) {
572	def, err := parsePoolParams(p.pctx.scope, &p.params)
573	if err != nil {
574		panic(fmt.Errorf("error parsing PoolParams for %s: %s", p, err))
575	}
576	return def, nil
577}
578
579func (p *staticPool) String() string {
580	return p.pctx.pkgPath + "." + p.name_
581}
582
583type poolFunc struct {
584	pctx       *packageContext
585	name_      string
586	paramsFunc func(interface{}) (PoolParams, error)
587	fullName_  string
588}
589
590// PoolFunc returns a Pool whose value is determined by a function that takes a
591// config object as input and returns either the pool parameters or an error. It
592// may only be called during a Go package's initialization - either from the
593// init() function or as part of a package-scoped variable's initialization.
594//
595// This function is usually used to initialize a package-scoped Go variable that
596// represents a Ninja pool that will be output.  The name argument should
597// exactly match the Go variable name, and the string fields of the PoolParams
598// returned by f may reference other Ninja variables that are visible within the
599// calling Go package.
600func (p *packageContext) PoolFunc(name string, f func(interface{}) (PoolParams,
601	error)) Pool {
602
603	checkCalledFromInit()
604
605	err := validateNinjaName(name)
606	if err != nil {
607		panic(err)
608	}
609
610	pool := &poolFunc{
611		pctx:       p,
612		name_:      name,
613		paramsFunc: f,
614	}
615	err = p.scope.AddPool(pool)
616	if err != nil {
617		panic(err)
618	}
619
620	return pool
621}
622
623func (p *poolFunc) packageContext() *packageContext {
624	return p.pctx
625}
626
627func (p *poolFunc) name() string {
628	return p.name_
629}
630
631func (p *poolFunc) fullName(pkgNames map[*packageContext]string) string {
632	if p.fullName_ != "" {
633		return p.fullName_
634	}
635	return packageNamespacePrefix(pkgNames[p.pctx]) + p.name_
636}
637
638func (p *poolFunc) memoizeFullName(pkgNames map[*packageContext]string) {
639	p.fullName_ = p.fullName(pkgNames)
640}
641
642func (p *poolFunc) def(config interface{}) (*poolDef, error) {
643	params, err := p.paramsFunc(config)
644	if err != nil {
645		return nil, err
646	}
647	def, err := parsePoolParams(p.pctx.scope, &params)
648	if err != nil {
649		panic(fmt.Errorf("error parsing PoolParams for %s: %s", p, err))
650	}
651	return def, nil
652}
653
654func (p *poolFunc) String() string {
655	return p.pctx.pkgPath + "." + p.name_
656}
657
658type builtinPool struct {
659	name_ string
660}
661
662func (p *builtinPool) packageContext() *packageContext {
663	return nil
664}
665
666func (p *builtinPool) name() string {
667	return p.name_
668}
669
670func (p *builtinPool) fullName(pkgNames map[*packageContext]string) string {
671	return p.name_
672}
673
674func (p *builtinPool) memoizeFullName(pkgNames map[*packageContext]string) {
675	// Nothing to do, full name is known at initialization.
676}
677
678func (p *builtinPool) def(config interface{}) (*poolDef, error) {
679	return nil, errPoolIsBuiltin
680}
681
682// NewBuiltinPool returns a Pool object that refers to a pool name created outside of Blueprint
683func NewBuiltinPool(name string) Pool {
684	return &builtinPool{
685		name_: name,
686	}
687}
688
689func (p *builtinPool) String() string {
690	return "<builtin>:" + p.name_
691}
692
693type staticRule struct {
694	pctx       *packageContext
695	name_      string
696	params     RuleParams
697	argNames   map[string]bool
698	scope_     *basicScope
699	fullName_  string
700	sync.Mutex // protects scope_ during lazy creation
701}
702
703// StaticRule returns a Rule whose value does not depend on any configuration
704// information.  It may only be called during a Go package's initialization -
705// either from the init() function or as part of a package-scoped Go variable's
706// initialization.
707//
708// This function is usually used to initialize a package-scoped Go variable that
709// represents a Ninja rule that will be output.  The name argument should
710// exactly match the Go variable name, and the params fields may reference other
711// Ninja variables that are visible within the calling Go package.
712//
713// The argNames arguments list Ninja variables that may be overridden by Ninja
714// build statements that invoke the rule.  These arguments may be referenced in
715// any of the string fields of params.  Arguments can shadow package-scoped
716// variables defined within the caller's Go package, but they may not shadow
717// those defined in another package.  Shadowing a package-scoped variable
718// results in the package-scoped variable's value being used for build
719// statements that do not override the argument.  For argument names that do not
720// shadow package-scoped variables the default value is an empty string.
721func (p *packageContext) StaticRule(name string, params RuleParams,
722	argNames ...string) Rule {
723
724	checkCalledFromInit()
725
726	err := validateNinjaName(name)
727	if err != nil {
728		panic(err)
729	}
730
731	err = validateArgNames(argNames)
732	if err != nil {
733		panic(fmt.Errorf("invalid argument name: %s", err))
734	}
735
736	argNamesSet := make(map[string]bool)
737	for _, argName := range argNames {
738		argNamesSet[argName] = true
739	}
740
741	ruleScope := (*basicScope)(nil) // This will get created lazily
742
743	r := &staticRule{
744		pctx:     p,
745		name_:    name,
746		params:   params,
747		argNames: argNamesSet,
748		scope_:   ruleScope,
749	}
750	err = p.scope.AddRule(r)
751	if err != nil {
752		panic(err)
753	}
754
755	return r
756}
757
758func (r *staticRule) packageContext() *packageContext {
759	return r.pctx
760}
761
762func (r *staticRule) name() string {
763	return r.name_
764}
765
766func (r *staticRule) fullName(pkgNames map[*packageContext]string) string {
767	if r.fullName_ != "" {
768		return r.fullName_
769	}
770	return packageNamespacePrefix(pkgNames[r.pctx]) + r.name_
771}
772
773func (r *staticRule) memoizeFullName(pkgNames map[*packageContext]string) {
774	r.fullName_ = r.fullName(pkgNames)
775}
776
777func (r *staticRule) def(interface{}) (*ruleDef, error) {
778	def, err := parseRuleParams(r.scope(), &r.params)
779	if err != nil {
780		panic(fmt.Errorf("error parsing RuleParams for %s: %s", r, err))
781	}
782	return def, nil
783}
784
785func (r *staticRule) scope() *basicScope {
786	// We lazily create the scope so that all the package-scoped variables get
787	// declared before the args are created.  Otherwise we could incorrectly
788	// shadow a package-scoped variable with an arg variable.
789	r.Lock()
790	defer r.Unlock()
791
792	if r.scope_ == nil {
793		r.scope_ = makeRuleScope(r.pctx.scope, r.argNames)
794	}
795	return r.scope_
796}
797
798func (r *staticRule) isArg(argName string) bool {
799	return r.argNames[argName]
800}
801
802func (r *staticRule) String() string {
803	return r.pctx.pkgPath + "." + r.name_
804}
805
806type ruleFunc struct {
807	pctx       *packageContext
808	name_      string
809	paramsFunc func(interface{}) (RuleParams, error)
810	argNames   map[string]bool
811	scope_     *basicScope
812	fullName_  string
813	sync.Mutex // protects scope_ during lazy creation
814}
815
816// RuleFunc returns a Rule whose value is determined by a function that takes a
817// config object as input and returns either the rule parameters or an error. It
818// may only be called during a Go package's initialization - either from the
819// init() function or as part of a package-scoped variable's initialization.
820//
821// This function is usually used to initialize a package-scoped Go variable that
822// represents a Ninja rule that will be output.  The name argument should
823// exactly match the Go variable name, and the string fields of the RuleParams
824// returned by f may reference other Ninja variables that are visible within the
825// calling Go package.
826//
827// The argNames arguments list Ninja variables that may be overridden by Ninja
828// build statements that invoke the rule.  These arguments may be referenced in
829// any of the string fields of the RuleParams returned by f.  Arguments can
830// shadow package-scoped variables defined within the caller's Go package, but
831// they may not shadow those defined in another package.  Shadowing a package-
832// scoped variable results in the package-scoped variable's value being used for
833// build statements that do not override the argument.  For argument names that
834// do not shadow package-scoped variables the default value is an empty string.
835func (p *packageContext) RuleFunc(name string, f func(interface{}) (RuleParams,
836	error), argNames ...string) Rule {
837
838	checkCalledFromInit()
839
840	err := validateNinjaName(name)
841	if err != nil {
842		panic(err)
843	}
844
845	err = validateArgNames(argNames)
846	if err != nil {
847		panic(fmt.Errorf("invalid argument name: %s", err))
848	}
849
850	argNamesSet := make(map[string]bool)
851	for _, argName := range argNames {
852		argNamesSet[argName] = true
853	}
854
855	ruleScope := (*basicScope)(nil) // This will get created lazily
856
857	rule := &ruleFunc{
858		pctx:       p,
859		name_:      name,
860		paramsFunc: f,
861		argNames:   argNamesSet,
862		scope_:     ruleScope,
863	}
864	err = p.scope.AddRule(rule)
865	if err != nil {
866		panic(err)
867	}
868
869	return rule
870}
871
872func (r *ruleFunc) packageContext() *packageContext {
873	return r.pctx
874}
875
876func (r *ruleFunc) name() string {
877	return r.name_
878}
879
880func (r *ruleFunc) fullName(pkgNames map[*packageContext]string) string {
881	if r.fullName_ != "" {
882		return r.fullName_
883	}
884	return packageNamespacePrefix(pkgNames[r.pctx]) + r.name_
885}
886
887func (r *ruleFunc) memoizeFullName(pkgNames map[*packageContext]string) {
888	r.fullName_ = r.fullName(pkgNames)
889}
890
891func (r *ruleFunc) def(config interface{}) (*ruleDef, error) {
892	params, err := r.paramsFunc(config)
893	if err != nil {
894		return nil, err
895	}
896	def, err := parseRuleParams(r.scope(), &params)
897	if err != nil {
898		panic(fmt.Errorf("error parsing RuleParams for %s: %s", r, err))
899	}
900	return def, nil
901}
902
903func (r *ruleFunc) scope() *basicScope {
904	// We lazily create the scope so that all the global variables get declared
905	// before the args are created.  Otherwise we could incorrectly shadow a
906	// global variable with an arg variable.
907	r.Lock()
908	defer r.Unlock()
909
910	if r.scope_ == nil {
911		r.scope_ = makeRuleScope(r.pctx.scope, r.argNames)
912	}
913	return r.scope_
914}
915
916func (r *ruleFunc) isArg(argName string) bool {
917	return r.argNames[argName]
918}
919
920func (r *ruleFunc) String() string {
921	return r.pctx.pkgPath + "." + r.name_
922}
923
924type builtinRule struct {
925	name_      string
926	scope_     *basicScope
927	sync.Mutex // protects scope_ during lazy creation
928}
929
930func (r *builtinRule) packageContext() *packageContext {
931	return nil
932}
933
934func (r *builtinRule) name() string {
935	return r.name_
936}
937
938func (r *builtinRule) fullName(pkgNames map[*packageContext]string) string {
939	return r.name_
940}
941
942func (r *builtinRule) memoizeFullName(pkgNames map[*packageContext]string) {
943	// Nothing to do, full name is known at initialization.
944}
945
946func (r *builtinRule) def(config interface{}) (*ruleDef, error) {
947	return nil, errRuleIsBuiltin
948}
949
950func (r *builtinRule) scope() *basicScope {
951	r.Lock()
952	defer r.Unlock()
953
954	if r.scope_ == nil {
955		r.scope_ = makeRuleScope(nil, nil)
956	}
957	return r.scope_
958}
959
960func (r *builtinRule) isArg(argName string) bool {
961	return false
962}
963
964func (r *builtinRule) String() string {
965	return "<builtin>:" + r.name_
966}
967
968// NewBuiltinRule returns a Rule object that refers to a rule that was created outside of Blueprint
969func NewBuiltinRule(name string) Rule {
970	return &builtinRule{
971		name_: name,
972	}
973}
974
975func (p *packageContext) AddNinjaFileDeps(deps ...string) {
976	p.ninjaFileDeps = append(p.ninjaFileDeps, deps...)
977}
978