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