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 "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 // } 57 type 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 76 type packageContext struct { 77 fullName string 78 shortName string 79 pkgPath string 80 scope *basicScope 81 ninjaFileDeps []string 82 } 83 84 var _ PackageContext = &packageContext{} 85 86 func (p *packageContext) getScope() *basicScope { 87 return p.scope 88 } 89 90 var 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. 96 func 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 124 var Phony Rule = NewBuiltinRule("phony") 125 126 var Console Pool = NewBuiltinPool("console") 127 128 var errRuleIsBuiltin = errors.New("the rule is a built-in") 129 var errPoolIsBuiltin = errors.New("the pool is a built-in") 130 var 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. 134 func 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. 150 var 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. 155 func 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. 178 func 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. 217 func (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. 233 func (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 251 type 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. 266 func (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 282 func (v *staticVariable) packageContext() *packageContext { 283 return v.pctx 284 } 285 286 func (v *staticVariable) name() string { 287 return v.name_ 288 } 289 290 func (v *staticVariable) fullName(pkgNames map[*packageContext]string) string { 291 return packageNamespacePrefix(pkgNames[v.pctx]) + v.name_ 292 } 293 294 func (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 303 func (v *staticVariable) String() string { 304 return v.pctx.pkgPath + "." + v.name_ 305 } 306 307 type 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. 324 func (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. 354 func (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 382 func (v *variableFunc) packageContext() *packageContext { 383 return v.pctx 384 } 385 386 func (v *variableFunc) name() string { 387 return v.name_ 388 } 389 390 func (v *variableFunc) fullName(pkgNames map[*packageContext]string) string { 391 return packageNamespacePrefix(pkgNames[v.pctx]) + v.name_ 392 } 393 394 func (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 409 func (v *variableFunc) String() string { 410 return v.pctx.pkgPath + "." + v.name_ 411 } 412 413 func 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. 438 type argVariable struct { 439 name_ string 440 } 441 442 func (v *argVariable) packageContext() *packageContext { 443 panic("this should not be called") 444 } 445 446 func (v *argVariable) name() string { 447 return v.name_ 448 } 449 450 func (v *argVariable) fullName(pkgNames map[*packageContext]string) string { 451 return v.name_ 452 } 453 454 func (v *argVariable) value(config interface{}) (*ninjaString, error) { 455 return nil, errVariableIsArg 456 } 457 458 func (v *argVariable) String() string { 459 return "<arg>:" + v.name_ 460 } 461 462 type 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. 477 func (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 494 func (p *staticPool) packageContext() *packageContext { 495 return p.pctx 496 } 497 498 func (p *staticPool) name() string { 499 return p.name_ 500 } 501 502 func (p *staticPool) fullName(pkgNames map[*packageContext]string) string { 503 return packageNamespacePrefix(pkgNames[p.pctx]) + p.name_ 504 } 505 506 func (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 514 func (p *staticPool) String() string { 515 return p.pctx.pkgPath + "." + p.name_ 516 } 517 518 type 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. 534 func (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 553 func (p *poolFunc) packageContext() *packageContext { 554 return p.pctx 555 } 556 557 func (p *poolFunc) name() string { 558 return p.name_ 559 } 560 561 func (p *poolFunc) fullName(pkgNames map[*packageContext]string) string { 562 return packageNamespacePrefix(pkgNames[p.pctx]) + p.name_ 563 } 564 565 func (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 577 func (p *poolFunc) String() string { 578 return p.pctx.pkgPath + "." + p.name_ 579 } 580 581 type builtinPool struct { 582 name_ string 583 } 584 585 func (p *builtinPool) packageContext() *packageContext { 586 return nil 587 } 588 589 func (p *builtinPool) name() string { 590 return p.name_ 591 } 592 593 func (p *builtinPool) fullName(pkgNames map[*packageContext]string) string { 594 return p.name_ 595 } 596 597 func (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 602 func NewBuiltinPool(name string) Pool { 603 return &builtinPool{ 604 name_: name, 605 } 606 } 607 608 func (p *builtinPool) String() string { 609 return "<builtin>:" + p.name_ 610 } 611 612 type 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. 639 func (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 676 func (r *staticRule) packageContext() *packageContext { 677 return r.pctx 678 } 679 680 func (r *staticRule) name() string { 681 return r.name_ 682 } 683 684 func (r *staticRule) fullName(pkgNames map[*packageContext]string) string { 685 return packageNamespacePrefix(pkgNames[r.pctx]) + r.name_ 686 } 687 688 func (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 696 func (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 709 func (r *staticRule) isArg(argName string) bool { 710 return r.argNames[argName] 711 } 712 713 func (r *staticRule) String() string { 714 return r.pctx.pkgPath + "." + r.name_ 715 } 716 717 type 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. 745 func (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 782 func (r *ruleFunc) packageContext() *packageContext { 783 return r.pctx 784 } 785 786 func (r *ruleFunc) name() string { 787 return r.name_ 788 } 789 790 func (r *ruleFunc) fullName(pkgNames map[*packageContext]string) string { 791 return packageNamespacePrefix(pkgNames[r.pctx]) + r.name_ 792 } 793 794 func (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 806 func (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 819 func (r *ruleFunc) isArg(argName string) bool { 820 return r.argNames[argName] 821 } 822 823 func (r *ruleFunc) String() string { 824 return r.pctx.pkgPath + "." + r.name_ 825 } 826 827 type builtinRule struct { 828 name_ string 829 scope_ *basicScope 830 sync.Mutex // protects scope_ during lazy creation 831 } 832 833 func (r *builtinRule) packageContext() *packageContext { 834 return nil 835 } 836 837 func (r *builtinRule) name() string { 838 return r.name_ 839 } 840 841 func (r *builtinRule) fullName(pkgNames map[*packageContext]string) string { 842 return r.name_ 843 } 844 845 func (r *builtinRule) def(config interface{}) (*ruleDef, error) { 846 return nil, errRuleIsBuiltin 847 } 848 849 func (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 859 func (r *builtinRule) isArg(argName string) bool { 860 return false 861 } 862 863 func (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 868 func NewBuiltinRule(name string) Rule { 869 return &builtinRule{ 870 name_: name, 871 } 872 } 873 874 func (p *packageContext) AddNinjaFileDeps(deps ...string) { 875 p.ninjaFileDeps = append(p.ninjaFileDeps, deps...) 876 } 877