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, ¶ms) 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(), ¶ms) 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