blob: 088239ece6a7435fd79595333022fd79550eaf8c [file] [log] [blame]
Colin Cross8e0c5112015-01-23 14:15:10 -08001// 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
Jamie Gennis1bc967e2014-05-27 16:34:41 -070015package blueprint
16
17import (
18 "errors"
19 "fmt"
Jamie Gennis28a63fb2014-06-05 19:50:44 -070020 "reflect"
Colin Crossf7104c02019-02-28 14:38:42 -080021 "regexp"
Jamie Gennis1bc967e2014-05-27 16:34:41 -070022 "runtime"
23 "strings"
Colin Cross691a60d2015-01-07 18:08:56 -080024 "sync"
Jamie Gennis1bc967e2014-05-27 16:34:41 -070025)
26
Jamie Gennis2fb20952014-10-03 02:49:58 -070027// 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// }
Dan Willemsenaeffbf72015-11-25 15:29:32 -080057type 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
Dan Willemsena481ae22015-12-18 15:18:03 -080071 AddNinjaFileDeps(deps ...string)
72
Dan Willemsenaeffbf72015-11-25 15:29:32 -080073 getScope() *basicScope
74}
75
76type packageContext struct {
Dan Willemsena481ae22015-12-18 15:18:03 -080077 fullName string
78 shortName string
79 pkgPath string
80 scope *basicScope
81 ninjaFileDeps []string
Jamie Gennis1bc967e2014-05-27 16:34:41 -070082}
Dan Willemsena481ae22015-12-18 15:18:03 -080083
Dan Willemsenaeffbf72015-11-25 15:29:32 -080084var _ PackageContext = &packageContext{}
Jamie Gennis1bc967e2014-05-27 16:34:41 -070085
Dan Willemsenaeffbf72015-11-25 15:29:32 -080086func (p *packageContext) getScope() *basicScope {
87 return p.scope
88}
89
90var packageContexts = map[string]*packageContext{}
Jamie Gennis2fb20952014-10-03 02:49:58 -070091
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.
Dan Willemsenaeffbf72015-11-25 15:29:32 -080096func NewPackageContext(pkgPath string) PackageContext {
Jamie Gennis2fb20952014-10-03 02:49:58 -070097 checkCalledFromInit()
98
99 if _, present := packageContexts[pkgPath]; present {
Colin Cross017ed2e2016-05-31 15:53:32 -0700100 panic(fmt.Errorf("package %q already has a package context", pkgPath))
Jamie Gennis2fb20952014-10-03 02:49:58 -0700101 }
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
Dan Willemsenaeffbf72015-11-25 15:29:32 -0800112 p := &packageContext{
Jamie Gennis2fb20952014-10-03 02:49:58 -0700113 fullName: pkgName,
114 shortName: shortName,
115 pkgPath: pkgPath,
116 scope: newScope(nil),
117 }
118
119 packageContexts[pkgPath] = p
120
121 return p
122}
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700123
Colin Crosse0e473e2016-08-29 15:07:16 -0700124var Phony Rule = NewBuiltinRule("phony")
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700125
Colin Crosse0e473e2016-08-29 15:07:16 -0700126var Console Pool = NewBuiltinPool("console")
Ken Oslund4b9a0512015-04-14 16:26:58 -0700127
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700128var errRuleIsBuiltin = errors.New("the rule is a built-in")
Ken Oslund4b9a0512015-04-14 16:26:58 -0700129var errPoolIsBuiltin = errors.New("the pool is a built-in")
Jamie Gennis28a63fb2014-06-05 19:50:44 -0700130var errVariableIsArg = errors.New("argument variables have no value")
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700131
Jamie Gennis2fb20952014-10-03 02:49:58 -0700132// 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
Colin Crossf7104c02019-02-28 14:38:42 -0800141 if funcName == "init" || strings.HasPrefix(funcName, "init·") ||
142 funcName == "init.ializers" || strings.HasPrefix(funcName, "init.") {
Jamie Gennis2fb20952014-10-03 02:49:58 -0700143 return
144 }
145 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700146}
147
Colin Crossf7104c02019-02-28 14:38:42 -0800148// 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
Jamie Gennis0ed63ef2014-06-30 18:07:17 -0700152// 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.
Jamie Gennis2fb20952014-10-03 02:49:58 -0700155func callerName(skip int) (pkgPath, funcName string, ok bool) {
Jamie Gennis0ed63ef2014-06-30 18:07:17 -0700156 var pc [1]uintptr
157 n := runtime.Callers(skip+1, pc[:])
158 if n != 1 {
Jamie Gennis2fb20952014-10-03 02:49:58 -0700159 return "", "", false
Jamie Gennis0ed63ef2014-06-30 18:07:17 -0700160 }
Jooyung Han5dd43cf2019-09-05 15:48:27 +0900161 frames := runtime.CallersFrames(pc[:])
162 frame, _ := frames.Next()
163 f := frame.Function
Colin Crossf7104c02019-02-28 14:38:42 -0800164 s := pkgPathRe.FindStringSubmatch(f)
165 if len(s) < 3 {
166 panic(fmt.Errorf("failed to extract package path and function name from %q", f))
Jamie Gennis0ed63ef2014-06-30 18:07:17 -0700167 }
168
Colin Crossf7104c02019-02-28 14:38:42 -0800169 return s[1], s[2], true
Jamie Gennis0ed63ef2014-06-30 18:07:17 -0700170}
171
Jamie Gennis2fb20952014-10-03 02:49:58 -0700172// 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)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700181}
182
Jamie Gennis2fb20952014-10-03 02:49:58 -0700183// 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:
Jamie Gennis28a63fb2014-06-05 19:50:44 -0700192//
193// import (
194// "blueprint"
195// "foo/bar"
196// )
197//
Jamie Gennis2fb20952014-10-03 02:49:58 -0700198// var pctx = NewPackagePath("blah")
199//
Jamie Gennis28a63fb2014-06-05 19:50:44 -0700200// func init() {
Jamie Gennis2fb20952014-10-03 02:49:58 -0700201// pctx.Import("foo/bar")
Jamie Gennis28a63fb2014-06-05 19:50:44 -0700202// }
203//
204// ...
205//
206// func (m *MyModule) GenerateBuildActions(ctx blueprint.Module) {
Jamie Gennis2fb20952014-10-03 02:49:58 -0700207// ctx.Build(pctx, blueprint.BuildParams{
Jamie Gennis28a63fb2014-06-05 19:50:44 -0700208// Rule: bar.SomeRule,
209// Outputs: []string{"${bar.SomeVariable}"},
210// })
211// }
Jamie Gennisd4e10182014-06-12 20:06:50 -0700212//
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.
Dan Willemsenaeffbf72015-11-25 15:29:32 -0800218func (p *packageContext) Import(pkgPath string) {
Jamie Gennis2fb20952014-10-03 02:49:58 -0700219 checkCalledFromInit()
220 importPkg, ok := packageContexts[pkgPath]
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700221 if !ok {
Jamie Gennis2fb20952014-10-03 02:49:58 -0700222 panic(fmt.Errorf("package %q has no context", pkgPath))
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700223 }
224
Jamie Gennis2fb20952014-10-03 02:49:58 -0700225 err := p.scope.AddImport(importPkg.shortName, importPkg.scope)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700226 if err != nil {
227 panic(err)
228 }
229}
230
Jamie Gennisd4e10182014-06-12 20:06:50 -0700231// 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.
Dan Willemsenaeffbf72015-11-25 15:29:32 -0800234func (p *packageContext) ImportAs(as, pkgPath string) {
Jamie Gennis2fb20952014-10-03 02:49:58 -0700235 checkCalledFromInit()
236 importPkg, ok := packageContexts[pkgPath]
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700237 if !ok {
Jamie Gennis2fb20952014-10-03 02:49:58 -0700238 panic(fmt.Errorf("package %q has no context", pkgPath))
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700239 }
240
241 err := validateNinjaName(as)
242 if err != nil {
243 panic(err)
244 }
245
Jamie Gennis2fb20952014-10-03 02:49:58 -0700246 err = p.scope.AddImport(as, importPkg.scope)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700247 if err != nil {
248 panic(err)
249 }
250}
251
252type staticVariable struct {
Dan Willemsenaeffbf72015-11-25 15:29:32 -0800253 pctx *packageContext
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700254 name_ string
255 value_ string
256}
257
Jamie Gennisd4e10182014-06-12 20:06:50 -0700258// 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.
Dan Willemsenaeffbf72015-11-25 15:29:32 -0800267func (p *packageContext) StaticVariable(name, value string) Variable {
Jamie Gennis2fb20952014-10-03 02:49:58 -0700268 checkCalledFromInit()
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700269 err := validateNinjaName(name)
270 if err != nil {
271 panic(err)
272 }
273
Jamie Gennis2fb20952014-10-03 02:49:58 -0700274 v := &staticVariable{p, name, value}
275 err = p.scope.AddVariable(v)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700276 if err != nil {
277 panic(err)
278 }
279
280 return v
281}
282
Dan Willemsenaeffbf72015-11-25 15:29:32 -0800283func (v *staticVariable) packageContext() *packageContext {
Jamie Gennis2fb20952014-10-03 02:49:58 -0700284 return v.pctx
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700285}
286
287func (v *staticVariable) name() string {
288 return v.name_
289}
290
Dan Willemsenaeffbf72015-11-25 15:29:32 -0800291func (v *staticVariable) fullName(pkgNames map[*packageContext]string) string {
Jamie Gennis2fb20952014-10-03 02:49:58 -0700292 return packageNamespacePrefix(pkgNames[v.pctx]) + v.name_
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700293}
294
Colin Cross2ce594e2020-01-29 12:58:03 -0800295func (v *staticVariable) value(interface{}) (ninjaString, error) {
Jamie Gennis2fb20952014-10-03 02:49:58 -0700296 ninjaStr, err := parseNinjaString(v.pctx.scope, v.value_)
Jamie Gennis71bd58a2014-06-13 18:19:16 -0700297 if err != nil {
Jamie Gennis48aed8c2014-06-13 18:25:54 -0700298 err = fmt.Errorf("error parsing variable %s value: %s", v, err)
Jamie Gennis71bd58a2014-06-13 18:19:16 -0700299 panic(err)
300 }
301 return ninjaStr, nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700302}
303
Jamie Gennis48aed8c2014-06-13 18:25:54 -0700304func (v *staticVariable) String() string {
Jamie Gennis2fb20952014-10-03 02:49:58 -0700305 return v.pctx.pkgPath + "." + v.name_
Jamie Gennis48aed8c2014-06-13 18:25:54 -0700306}
307
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700308type variableFunc struct {
Dan Willemsenaeffbf72015-11-25 15:29:32 -0800309 pctx *packageContext
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700310 name_ string
Jamie Gennis6eb4d242014-06-11 18:31:16 -0700311 value_ func(interface{}) (string, error)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700312}
313
314// VariableFunc returns a Variable whose value is determined by a function that
Jamie Gennisd4e10182014-06-12 20:06:50 -0700315// 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.
Dan Willemsenaeffbf72015-11-25 15:29:32 -0800325func (p *packageContext) VariableFunc(name string,
Jamie Gennis2fb20952014-10-03 02:49:58 -0700326 f func(config interface{}) (string, error)) Variable {
327
328 checkCalledFromInit()
Jamie Gennisd4e10182014-06-12 20:06:50 -0700329
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700330 err := validateNinjaName(name)
331 if err != nil {
332 panic(err)
333 }
334
Jamie Gennis2fb20952014-10-03 02:49:58 -0700335 v := &variableFunc{p, name, f}
336 err = p.scope.AddVariable(v)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700337 if err != nil {
338 panic(err)
339 }
340
341 return v
342}
343
Jamie Gennis28a63fb2014-06-05 19:50:44 -0700344// VariableConfigMethod returns a Variable whose value is determined by calling
Jamie Gennisd4e10182014-06-12 20:06:50 -0700345// 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.
Dan Willemsenaeffbf72015-11-25 15:29:32 -0800355func (p *packageContext) VariableConfigMethod(name string,
Jamie Gennis2fb20952014-10-03 02:49:58 -0700356 method interface{}) Variable {
357
358 checkCalledFromInit()
359
Jamie Gennis28a63fb2014-06-05 19:50:44 -0700360 err := validateNinjaName(name)
361 if err != nil {
362 panic(err)
363 }
364
Jamie Gennis28a63fb2014-06-05 19:50:44 -0700365 methodValue := reflect.ValueOf(method)
366 validateVariableMethod(name, methodValue)
367
Jamie Gennis6eb4d242014-06-11 18:31:16 -0700368 fun := func(config interface{}) (string, error) {
Jamie Gennis28a63fb2014-06-05 19:50:44 -0700369 result := methodValue.Call([]reflect.Value{reflect.ValueOf(config)})
370 resultStr := result[0].Interface().(string)
371 return resultStr, nil
372 }
373
Jamie Gennis2fb20952014-10-03 02:49:58 -0700374 v := &variableFunc{p, name, fun}
375 err = p.scope.AddVariable(v)
Jamie Gennis28a63fb2014-06-05 19:50:44 -0700376 if err != nil {
377 panic(err)
378 }
379
380 return v
381}
382
Dan Willemsenaeffbf72015-11-25 15:29:32 -0800383func (v *variableFunc) packageContext() *packageContext {
Jamie Gennis2fb20952014-10-03 02:49:58 -0700384 return v.pctx
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700385}
386
387func (v *variableFunc) name() string {
388 return v.name_
389}
390
Dan Willemsenaeffbf72015-11-25 15:29:32 -0800391func (v *variableFunc) fullName(pkgNames map[*packageContext]string) string {
Jamie Gennis2fb20952014-10-03 02:49:58 -0700392 return packageNamespacePrefix(pkgNames[v.pctx]) + v.name_
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700393}
394
Colin Cross2ce594e2020-01-29 12:58:03 -0800395func (v *variableFunc) value(config interface{}) (ninjaString, error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700396 value, err := v.value_(config)
397 if err != nil {
398 return nil, err
399 }
Jamie Gennis71bd58a2014-06-13 18:19:16 -0700400
Jamie Gennis2fb20952014-10-03 02:49:58 -0700401 ninjaStr, err := parseNinjaString(v.pctx.scope, value)
Jamie Gennis71bd58a2014-06-13 18:19:16 -0700402 if err != nil {
Jamie Gennis48aed8c2014-06-13 18:25:54 -0700403 err = fmt.Errorf("error parsing variable %s value: %s", v, err)
Jamie Gennis71bd58a2014-06-13 18:19:16 -0700404 panic(err)
405 }
406
407 return ninjaStr, nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700408}
409
Jamie Gennis48aed8c2014-06-13 18:25:54 -0700410func (v *variableFunc) String() string {
Jamie Gennis2fb20952014-10-03 02:49:58 -0700411 return v.pctx.pkgPath + "." + v.name_
Jamie Gennis48aed8c2014-06-13 18:25:54 -0700412}
413
Jamie Gennis28a63fb2014-06-05 19:50:44 -0700414func 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
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700434// 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
Dan Willemsenaeffbf72015-11-25 15:29:32 -0800443func (v *argVariable) packageContext() *packageContext {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700444 panic("this should not be called")
445}
446
447func (v *argVariable) name() string {
448 return v.name_
449}
450
Dan Willemsenaeffbf72015-11-25 15:29:32 -0800451func (v *argVariable) fullName(pkgNames map[*packageContext]string) string {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700452 return v.name_
453}
454
Colin Cross2ce594e2020-01-29 12:58:03 -0800455func (v *argVariable) value(config interface{}) (ninjaString, error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700456 return nil, errVariableIsArg
457}
458
Jamie Gennis48aed8c2014-06-13 18:25:54 -0700459func (v *argVariable) String() string {
460 return "<arg>:" + v.name_
461}
462
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700463type staticPool struct {
Dan Willemsenaeffbf72015-11-25 15:29:32 -0800464 pctx *packageContext
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700465 name_ string
466 params PoolParams
467}
468
Jamie Gennisd4e10182014-06-12 20:06:50 -0700469// 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.
Dan Willemsenaeffbf72015-11-25 15:29:32 -0800478func (p *packageContext) StaticPool(name string, params PoolParams) Pool {
Jamie Gennis2fb20952014-10-03 02:49:58 -0700479 checkCalledFromInit()
480
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700481 err := validateNinjaName(name)
482 if err != nil {
483 panic(err)
484 }
485
Jamie Gennis2fb20952014-10-03 02:49:58 -0700486 pool := &staticPool{p, name, params}
487 err = p.scope.AddPool(pool)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700488 if err != nil {
489 panic(err)
490 }
491
Jamie Gennis2fb20952014-10-03 02:49:58 -0700492 return pool
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700493}
494
Dan Willemsenaeffbf72015-11-25 15:29:32 -0800495func (p *staticPool) packageContext() *packageContext {
Jamie Gennis2fb20952014-10-03 02:49:58 -0700496 return p.pctx
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700497}
498
499func (p *staticPool) name() string {
500 return p.name_
501}
502
Dan Willemsenaeffbf72015-11-25 15:29:32 -0800503func (p *staticPool) fullName(pkgNames map[*packageContext]string) string {
Jamie Gennis2fb20952014-10-03 02:49:58 -0700504 return packageNamespacePrefix(pkgNames[p.pctx]) + p.name_
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700505}
506
Jamie Gennis6eb4d242014-06-11 18:31:16 -0700507func (p *staticPool) def(config interface{}) (*poolDef, error) {
Jamie Gennis2fb20952014-10-03 02:49:58 -0700508 def, err := parsePoolParams(p.pctx.scope, &p.params)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700509 if err != nil {
Jamie Gennis48aed8c2014-06-13 18:25:54 -0700510 panic(fmt.Errorf("error parsing PoolParams for %s: %s", p, err))
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700511 }
512 return def, nil
513}
514
Jamie Gennis48aed8c2014-06-13 18:25:54 -0700515func (p *staticPool) String() string {
Jamie Gennis2fb20952014-10-03 02:49:58 -0700516 return p.pctx.pkgPath + "." + p.name_
Jamie Gennis48aed8c2014-06-13 18:25:54 -0700517}
518
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700519type poolFunc struct {
Dan Willemsenaeffbf72015-11-25 15:29:32 -0800520 pctx *packageContext
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700521 name_ string
Jamie Gennis6eb4d242014-06-11 18:31:16 -0700522 paramsFunc func(interface{}) (PoolParams, error)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700523}
524
Jamie Gennisd4e10182014-06-12 20:06:50 -0700525// 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.
Dan Willemsenaeffbf72015-11-25 15:29:32 -0800535func (p *packageContext) PoolFunc(name string, f func(interface{}) (PoolParams,
Jamie Gennis2fb20952014-10-03 02:49:58 -0700536 error)) Pool {
537
538 checkCalledFromInit()
539
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700540 err := validateNinjaName(name)
541 if err != nil {
542 panic(err)
543 }
544
Jamie Gennis2fb20952014-10-03 02:49:58 -0700545 pool := &poolFunc{p, name, f}
546 err = p.scope.AddPool(pool)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700547 if err != nil {
548 panic(err)
549 }
550
Jamie Gennis2fb20952014-10-03 02:49:58 -0700551 return pool
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700552}
553
Dan Willemsenaeffbf72015-11-25 15:29:32 -0800554func (p *poolFunc) packageContext() *packageContext {
Jamie Gennis2fb20952014-10-03 02:49:58 -0700555 return p.pctx
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700556}
557
558func (p *poolFunc) name() string {
559 return p.name_
560}
561
Dan Willemsenaeffbf72015-11-25 15:29:32 -0800562func (p *poolFunc) fullName(pkgNames map[*packageContext]string) string {
Jamie Gennis2fb20952014-10-03 02:49:58 -0700563 return packageNamespacePrefix(pkgNames[p.pctx]) + p.name_
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700564}
565
Jamie Gennis6eb4d242014-06-11 18:31:16 -0700566func (p *poolFunc) def(config interface{}) (*poolDef, error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700567 params, err := p.paramsFunc(config)
568 if err != nil {
569 return nil, err
570 }
Jamie Gennis2fb20952014-10-03 02:49:58 -0700571 def, err := parsePoolParams(p.pctx.scope, &params)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700572 if err != nil {
Jamie Gennis48aed8c2014-06-13 18:25:54 -0700573 panic(fmt.Errorf("error parsing PoolParams for %s: %s", p, err))
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700574 }
575 return def, nil
576}
577
Jamie Gennis48aed8c2014-06-13 18:25:54 -0700578func (p *poolFunc) String() string {
Jamie Gennis2fb20952014-10-03 02:49:58 -0700579 return p.pctx.pkgPath + "." + p.name_
Jamie Gennis48aed8c2014-06-13 18:25:54 -0700580}
581
Ken Oslund4b9a0512015-04-14 16:26:58 -0700582type builtinPool struct {
Colin Cross63d5d4d2015-04-20 16:41:55 -0700583 name_ string
Ken Oslund4b9a0512015-04-14 16:26:58 -0700584}
585
Dan Willemsenaeffbf72015-11-25 15:29:32 -0800586func (p *builtinPool) packageContext() *packageContext {
Ken Oslund4b9a0512015-04-14 16:26:58 -0700587 return nil
588}
589
590func (p *builtinPool) name() string {
591 return p.name_
592}
593
Dan Willemsenaeffbf72015-11-25 15:29:32 -0800594func (p *builtinPool) fullName(pkgNames map[*packageContext]string) string {
Ken Oslund4b9a0512015-04-14 16:26:58 -0700595 return p.name_
596}
597
598func (p *builtinPool) def(config interface{}) (*poolDef, error) {
599 return nil, errPoolIsBuiltin
600}
601
Colin Crosse0e473e2016-08-29 15:07:16 -0700602// 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
Ken Oslund4b9a0512015-04-14 16:26:58 -0700609func (p *builtinPool) String() string {
610 return "<builtin>:" + p.name_
611}
612
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700613type staticRule struct {
Dan Willemsenaeffbf72015-11-25 15:29:32 -0800614 pctx *packageContext
Colin Cross691a60d2015-01-07 18:08:56 -0800615 name_ string
616 params RuleParams
617 argNames map[string]bool
618 scope_ *basicScope
619 sync.Mutex // protects scope_ during lazy creation
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700620}
621
Jamie Gennisd4e10182014-06-12 20:06:50 -0700622// 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.
Dan Willemsenaeffbf72015-11-25 15:29:32 -0800640func (p *packageContext) StaticRule(name string, params RuleParams,
Jamie Gennis2fb20952014-10-03 02:49:58 -0700641 argNames ...string) Rule {
642
643 checkCalledFromInit()
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700644
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
Jamie Gennis48aed8c2014-06-13 18:25:54 -0700660 ruleScope := (*basicScope)(nil) // This will get created lazily
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700661
Colin Cross691a60d2015-01-07 18:08:56 -0800662 r := &staticRule{
663 pctx: p,
664 name_: name,
665 params: params,
666 argNames: argNamesSet,
667 scope_: ruleScope,
668 }
Jamie Gennis2fb20952014-10-03 02:49:58 -0700669 err = p.scope.AddRule(r)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700670 if err != nil {
671 panic(err)
672 }
673
674 return r
675}
676
Dan Willemsenaeffbf72015-11-25 15:29:32 -0800677func (r *staticRule) packageContext() *packageContext {
Jamie Gennis2fb20952014-10-03 02:49:58 -0700678 return r.pctx
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700679}
680
681func (r *staticRule) name() string {
682 return r.name_
683}
684
Dan Willemsenaeffbf72015-11-25 15:29:32 -0800685func (r *staticRule) fullName(pkgNames map[*packageContext]string) string {
Jamie Gennis2fb20952014-10-03 02:49:58 -0700686 return packageNamespacePrefix(pkgNames[r.pctx]) + r.name_
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700687}
688
Jamie Gennis6eb4d242014-06-11 18:31:16 -0700689func (r *staticRule) def(interface{}) (*ruleDef, error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700690 def, err := parseRuleParams(r.scope(), &r.params)
691 if err != nil {
Jamie Gennis48aed8c2014-06-13 18:25:54 -0700692 panic(fmt.Errorf("error parsing RuleParams for %s: %s", r, err))
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700693 }
694 return def, nil
695}
696
Jamie Gennis48aed8c2014-06-13 18:25:54 -0700697func (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.
Colin Cross691a60d2015-01-07 18:08:56 -0800701 r.Lock()
702 defer r.Unlock()
703
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700704 if r.scope_ == nil {
Jamie Gennis2fb20952014-10-03 02:49:58 -0700705 r.scope_ = makeRuleScope(r.pctx.scope, r.argNames)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700706 }
707 return r.scope_
708}
709
710func (r *staticRule) isArg(argName string) bool {
711 return r.argNames[argName]
712}
713
Jamie Gennis48aed8c2014-06-13 18:25:54 -0700714func (r *staticRule) String() string {
Jamie Gennis2fb20952014-10-03 02:49:58 -0700715 return r.pctx.pkgPath + "." + r.name_
Jamie Gennis48aed8c2014-06-13 18:25:54 -0700716}
717
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700718type ruleFunc struct {
Dan Willemsenaeffbf72015-11-25 15:29:32 -0800719 pctx *packageContext
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700720 name_ string
Jamie Gennis6eb4d242014-06-11 18:31:16 -0700721 paramsFunc func(interface{}) (RuleParams, error)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700722 argNames map[string]bool
Jamie Gennis48aed8c2014-06-13 18:25:54 -0700723 scope_ *basicScope
Colin Cross691a60d2015-01-07 18:08:56 -0800724 sync.Mutex // protects scope_ during lazy creation
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700725}
726
Jamie Gennisd4e10182014-06-12 20:06:50 -0700727// 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.
Dan Willemsenaeffbf72015-11-25 15:29:32 -0800746func (p *packageContext) RuleFunc(name string, f func(interface{}) (RuleParams,
Jamie Gennis2fb20952014-10-03 02:49:58 -0700747 error), argNames ...string) Rule {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700748
Jamie Gennis2fb20952014-10-03 02:49:58 -0700749 checkCalledFromInit()
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700750
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
Jamie Gennis48aed8c2014-06-13 18:25:54 -0700766 ruleScope := (*basicScope)(nil) // This will get created lazily
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700767
Colin Cross691a60d2015-01-07 18:08:56 -0800768 rule := &ruleFunc{
769 pctx: p,
770 name_: name,
771 paramsFunc: f,
772 argNames: argNamesSet,
773 scope_: ruleScope,
774 }
Jamie Gennis2fb20952014-10-03 02:49:58 -0700775 err = p.scope.AddRule(rule)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700776 if err != nil {
777 panic(err)
778 }
779
Jamie Gennis2fb20952014-10-03 02:49:58 -0700780 return rule
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700781}
782
Dan Willemsenaeffbf72015-11-25 15:29:32 -0800783func (r *ruleFunc) packageContext() *packageContext {
Jamie Gennis2fb20952014-10-03 02:49:58 -0700784 return r.pctx
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700785}
786
787func (r *ruleFunc) name() string {
788 return r.name_
789}
790
Dan Willemsenaeffbf72015-11-25 15:29:32 -0800791func (r *ruleFunc) fullName(pkgNames map[*packageContext]string) string {
Jamie Gennis2fb20952014-10-03 02:49:58 -0700792 return packageNamespacePrefix(pkgNames[r.pctx]) + r.name_
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700793}
794
Jamie Gennis6eb4d242014-06-11 18:31:16 -0700795func (r *ruleFunc) def(config interface{}) (*ruleDef, error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700796 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 {
Jamie Gennis48aed8c2014-06-13 18:25:54 -0700802 panic(fmt.Errorf("error parsing RuleParams for %s: %s", r, err))
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700803 }
804 return def, nil
805}
806
Jamie Gennis48aed8c2014-06-13 18:25:54 -0700807func (r *ruleFunc) scope() *basicScope {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700808 // 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.
Colin Cross691a60d2015-01-07 18:08:56 -0800811 r.Lock()
812 defer r.Unlock()
813
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700814 if r.scope_ == nil {
Jamie Gennis2fb20952014-10-03 02:49:58 -0700815 r.scope_ = makeRuleScope(r.pctx.scope, r.argNames)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700816 }
817 return r.scope_
818}
819
820func (r *ruleFunc) isArg(argName string) bool {
821 return r.argNames[argName]
822}
823
Jamie Gennis48aed8c2014-06-13 18:25:54 -0700824func (r *ruleFunc) String() string {
Jamie Gennis2fb20952014-10-03 02:49:58 -0700825 return r.pctx.pkgPath + "." + r.name_
Jamie Gennis48aed8c2014-06-13 18:25:54 -0700826}
827
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700828type builtinRule struct {
Colin Cross691a60d2015-01-07 18:08:56 -0800829 name_ string
830 scope_ *basicScope
831 sync.Mutex // protects scope_ during lazy creation
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700832}
833
Dan Willemsenaeffbf72015-11-25 15:29:32 -0800834func (r *builtinRule) packageContext() *packageContext {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700835 return nil
836}
837
838func (r *builtinRule) name() string {
839 return r.name_
840}
841
Dan Willemsenaeffbf72015-11-25 15:29:32 -0800842func (r *builtinRule) fullName(pkgNames map[*packageContext]string) string {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700843 return r.name_
844}
845
Jamie Gennis6eb4d242014-06-11 18:31:16 -0700846func (r *builtinRule) def(config interface{}) (*ruleDef, error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700847 return nil, errRuleIsBuiltin
848}
849
Jamie Gennis48aed8c2014-06-13 18:25:54 -0700850func (r *builtinRule) scope() *basicScope {
Colin Cross691a60d2015-01-07 18:08:56 -0800851 r.Lock()
852 defer r.Unlock()
853
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700854 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
Jamie Gennis48aed8c2014-06-13 18:25:54 -0700864func (r *builtinRule) String() string {
865 return "<builtin>:" + r.name_
866}
Dan Willemsena481ae22015-12-18 15:18:03 -0800867
Colin Crosse0e473e2016-08-29 15:07:16 -0700868// 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
Dan Willemsena481ae22015-12-18 15:18:03 -0800875func (p *packageContext) AddNinjaFileDeps(deps ...string) {
876 p.ninjaFileDeps = append(p.ninjaFileDeps, deps...)
877}