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 15 package blueprint 16 17 import ( 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 // } 56 type 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 75 type packageContext struct { 76 fullName string 77 shortName string 78 pkgPath string 79 scope *basicScope 80 ninjaFileDeps []string 81 } 82 83 var _ PackageContext = &packageContext{} 84 85 func (p *packageContext) getScope() *basicScope { 86 return p.scope 87 } 88 89 var 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. 95 func 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 123 var Phony Rule = &builtinRule{ 124 name_: "phony", 125 } 126 127 var Console Pool = &builtinPool{ 128 name_: "console", 129 } 130 131 var errRuleIsBuiltin = errors.New("the rule is a built-in") 132 var errPoolIsBuiltin = errors.New("the pool is a built-in") 133 var 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. 137 func 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. 153 func 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. 188 func 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. 227 func (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. 243 func (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 261 type 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. 276 func (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 292 func (v *staticVariable) packageContext() *packageContext { 293 return v.pctx 294 } 295 296 func (v *staticVariable) name() string { 297 return v.name_ 298 } 299 300 func (v *staticVariable) fullName(pkgNames map[*packageContext]string) string { 301 return packageNamespacePrefix(pkgNames[v.pctx]) + v.name_ 302 } 303 304 func (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 313 func (v *staticVariable) String() string { 314 return v.pctx.pkgPath + "." + v.name_ 315 } 316 317 type 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. 334 func (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. 364 func (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 392 func (v *variableFunc) packageContext() *packageContext { 393 return v.pctx 394 } 395 396 func (v *variableFunc) name() string { 397 return v.name_ 398 } 399 400 func (v *variableFunc) fullName(pkgNames map[*packageContext]string) string { 401 return packageNamespacePrefix(pkgNames[v.pctx]) + v.name_ 402 } 403 404 func (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 419 func (v *variableFunc) String() string { 420 return v.pctx.pkgPath + "." + v.name_ 421 } 422 423 func 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. 448 type argVariable struct { 449 name_ string 450 } 451 452 func (v *argVariable) packageContext() *packageContext { 453 panic("this should not be called") 454 } 455 456 func (v *argVariable) name() string { 457 return v.name_ 458 } 459 460 func (v *argVariable) fullName(pkgNames map[*packageContext]string) string { 461 return v.name_ 462 } 463 464 func (v *argVariable) value(config interface{}) (*ninjaString, error) { 465 return nil, errVariableIsArg 466 } 467 468 func (v *argVariable) String() string { 469 return "<arg>:" + v.name_ 470 } 471 472 type 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. 487 func (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 504 func (p *staticPool) packageContext() *packageContext { 505 return p.pctx 506 } 507 508 func (p *staticPool) name() string { 509 return p.name_ 510 } 511 512 func (p *staticPool) fullName(pkgNames map[*packageContext]string) string { 513 return packageNamespacePrefix(pkgNames[p.pctx]) + p.name_ 514 } 515 516 func (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 524 func (p *staticPool) String() string { 525 return p.pctx.pkgPath + "." + p.name_ 526 } 527 528 type 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. 544 func (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 563 func (p *poolFunc) packageContext() *packageContext { 564 return p.pctx 565 } 566 567 func (p *poolFunc) name() string { 568 return p.name_ 569 } 570 571 func (p *poolFunc) fullName(pkgNames map[*packageContext]string) string { 572 return packageNamespacePrefix(pkgNames[p.pctx]) + p.name_ 573 } 574 575 func (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 587 func (p *poolFunc) String() string { 588 return p.pctx.pkgPath + "." + p.name_ 589 } 590 591 type builtinPool struct { 592 name_ string 593 } 594 595 func (p *builtinPool) packageContext() *packageContext { 596 return nil 597 } 598 599 func (p *builtinPool) name() string { 600 return p.name_ 601 } 602 603 func (p *builtinPool) fullName(pkgNames map[*packageContext]string) string { 604 return p.name_ 605 } 606 607 func (p *builtinPool) def(config interface{}) (*poolDef, error) { 608 return nil, errPoolIsBuiltin 609 } 610 611 func (p *builtinPool) String() string { 612 return "<builtin>:" + p.name_ 613 } 614 615 type 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. 642 func (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 679 func (r *staticRule) packageContext() *packageContext { 680 return r.pctx 681 } 682 683 func (r *staticRule) name() string { 684 return r.name_ 685 } 686 687 func (r *staticRule) fullName(pkgNames map[*packageContext]string) string { 688 return packageNamespacePrefix(pkgNames[r.pctx]) + r.name_ 689 } 690 691 func (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 699 func (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 712 func (r *staticRule) isArg(argName string) bool { 713 return r.argNames[argName] 714 } 715 716 func (r *staticRule) String() string { 717 return r.pctx.pkgPath + "." + r.name_ 718 } 719 720 type 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. 748 func (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 785 func (r *ruleFunc) packageContext() *packageContext { 786 return r.pctx 787 } 788 789 func (r *ruleFunc) name() string { 790 return r.name_ 791 } 792 793 func (r *ruleFunc) fullName(pkgNames map[*packageContext]string) string { 794 return packageNamespacePrefix(pkgNames[r.pctx]) + r.name_ 795 } 796 797 func (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 809 func (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 822 func (r *ruleFunc) isArg(argName string) bool { 823 return r.argNames[argName] 824 } 825 826 func (r *ruleFunc) String() string { 827 return r.pctx.pkgPath + "." + r.name_ 828 } 829 830 type builtinRule struct { 831 name_ string 832 scope_ *basicScope 833 sync.Mutex // protects scope_ during lazy creation 834 } 835 836 func (r *builtinRule) packageContext() *packageContext { 837 return nil 838 } 839 840 func (r *builtinRule) name() string { 841 return r.name_ 842 } 843 844 func (r *builtinRule) fullName(pkgNames map[*packageContext]string) string { 845 return r.name_ 846 } 847 848 func (r *builtinRule) def(config interface{}) (*ruleDef, error) { 849 return nil, errRuleIsBuiltin 850 } 851 852 func (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 862 func (r *builtinRule) isArg(argName string) bool { 863 return false 864 } 865 866 func (r *builtinRule) String() string { 867 return "<builtin>:" + r.name_ 868 } 869 870 func (p *packageContext) AddNinjaFileDeps(deps ...string) { 871 p.ninjaFileDeps = append(p.ninjaFileDeps, deps...) 872 } 873