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