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