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