1*1fa6dee9SAndroid Build Coastguard Worker// Copyright 2014 Google Inc. All rights reserved. 2*1fa6dee9SAndroid Build Coastguard Worker// 3*1fa6dee9SAndroid Build Coastguard Worker// Licensed under the Apache License, Version 2.0 (the "License"); 4*1fa6dee9SAndroid Build Coastguard Worker// you may not use this file except in compliance with the License. 5*1fa6dee9SAndroid Build Coastguard Worker// You may obtain a copy of the License at 6*1fa6dee9SAndroid Build Coastguard Worker// 7*1fa6dee9SAndroid Build Coastguard Worker// http://www.apache.org/licenses/LICENSE-2.0 8*1fa6dee9SAndroid Build Coastguard Worker// 9*1fa6dee9SAndroid Build Coastguard Worker// Unless required by applicable law or agreed to in writing, software 10*1fa6dee9SAndroid Build Coastguard Worker// distributed under the License is distributed on an "AS IS" BASIS, 11*1fa6dee9SAndroid Build Coastguard Worker// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12*1fa6dee9SAndroid Build Coastguard Worker// See the License for the specific language governing permissions and 13*1fa6dee9SAndroid Build Coastguard Worker// limitations under the License. 14*1fa6dee9SAndroid Build Coastguard Worker 15*1fa6dee9SAndroid Build Coastguard Workerpackage blueprint 16*1fa6dee9SAndroid Build Coastguard Worker 17*1fa6dee9SAndroid Build Coastguard Workerimport ( 18*1fa6dee9SAndroid Build Coastguard Worker "errors" 19*1fa6dee9SAndroid Build Coastguard Worker "fmt" 20*1fa6dee9SAndroid Build Coastguard Worker "sort" 21*1fa6dee9SAndroid Build Coastguard Worker "strconv" 22*1fa6dee9SAndroid Build Coastguard Worker "strings" 23*1fa6dee9SAndroid Build Coastguard Worker) 24*1fa6dee9SAndroid Build Coastguard Worker 25*1fa6dee9SAndroid Build Coastguard Worker// A Deps value indicates the dependency file format that Ninja should expect to 26*1fa6dee9SAndroid Build Coastguard Worker// be output by a compiler. 27*1fa6dee9SAndroid Build Coastguard Workertype Deps int 28*1fa6dee9SAndroid Build Coastguard Worker 29*1fa6dee9SAndroid Build Coastguard Workerconst ( 30*1fa6dee9SAndroid Build Coastguard Worker DepsNone Deps = iota 31*1fa6dee9SAndroid Build Coastguard Worker DepsGCC 32*1fa6dee9SAndroid Build Coastguard Worker DepsMSVC 33*1fa6dee9SAndroid Build Coastguard Worker) 34*1fa6dee9SAndroid Build Coastguard Worker 35*1fa6dee9SAndroid Build Coastguard Workerfunc (d Deps) String() string { 36*1fa6dee9SAndroid Build Coastguard Worker switch d { 37*1fa6dee9SAndroid Build Coastguard Worker case DepsNone: 38*1fa6dee9SAndroid Build Coastguard Worker return "none" 39*1fa6dee9SAndroid Build Coastguard Worker case DepsGCC: 40*1fa6dee9SAndroid Build Coastguard Worker return "gcc" 41*1fa6dee9SAndroid Build Coastguard Worker case DepsMSVC: 42*1fa6dee9SAndroid Build Coastguard Worker return "msvc" 43*1fa6dee9SAndroid Build Coastguard Worker default: 44*1fa6dee9SAndroid Build Coastguard Worker panic(fmt.Sprintf("unknown deps value: %d", d)) 45*1fa6dee9SAndroid Build Coastguard Worker } 46*1fa6dee9SAndroid Build Coastguard Worker} 47*1fa6dee9SAndroid Build Coastguard Worker 48*1fa6dee9SAndroid Build Coastguard Worker// A PoolParams object contains the set of parameters that make up a Ninja pool 49*1fa6dee9SAndroid Build Coastguard Worker// definition. 50*1fa6dee9SAndroid Build Coastguard Workertype PoolParams struct { 51*1fa6dee9SAndroid Build Coastguard Worker Comment string // The comment that will appear above the definition. 52*1fa6dee9SAndroid Build Coastguard Worker Depth int // The Ninja pool depth. 53*1fa6dee9SAndroid Build Coastguard Worker} 54*1fa6dee9SAndroid Build Coastguard Worker 55*1fa6dee9SAndroid Build Coastguard Worker// A RuleParams object contains the set of parameters that make up a Ninja rule 56*1fa6dee9SAndroid Build Coastguard Worker// definition. 57*1fa6dee9SAndroid Build Coastguard Workertype RuleParams struct { 58*1fa6dee9SAndroid Build Coastguard Worker // These fields correspond to a Ninja variable of the same name. 59*1fa6dee9SAndroid Build Coastguard Worker Command string // The command that Ninja will run for the rule. 60*1fa6dee9SAndroid Build Coastguard Worker Depfile string // The dependency file name. 61*1fa6dee9SAndroid Build Coastguard Worker Deps Deps // The format of the dependency file. 62*1fa6dee9SAndroid Build Coastguard Worker Description string // The description that Ninja will print for the rule. 63*1fa6dee9SAndroid Build Coastguard Worker Generator bool // Whether the rule generates the Ninja manifest file. 64*1fa6dee9SAndroid Build Coastguard Worker Pool Pool // The Ninja pool to which the rule belongs. 65*1fa6dee9SAndroid Build Coastguard Worker Restat bool // Whether Ninja should re-stat the rule's outputs. 66*1fa6dee9SAndroid Build Coastguard Worker Rspfile string // The response file. 67*1fa6dee9SAndroid Build Coastguard Worker RspfileContent string // The response file content. 68*1fa6dee9SAndroid Build Coastguard Worker 69*1fa6dee9SAndroid Build Coastguard Worker // These fields are used internally in Blueprint 70*1fa6dee9SAndroid Build Coastguard Worker CommandDeps []string // Command-specific implicit dependencies to prepend to builds 71*1fa6dee9SAndroid Build Coastguard Worker CommandOrderOnly []string // Command-specific order-only dependencies to prepend to builds 72*1fa6dee9SAndroid Build Coastguard Worker Comment string // The comment that will appear above the definition. 73*1fa6dee9SAndroid Build Coastguard Worker} 74*1fa6dee9SAndroid Build Coastguard Worker 75*1fa6dee9SAndroid Build Coastguard Worker// A BuildParams object contains the set of parameters that make up a Ninja 76*1fa6dee9SAndroid Build Coastguard Worker// build statement. Each field except for Args corresponds with a part of the 77*1fa6dee9SAndroid Build Coastguard Worker// Ninja build statement. The Args field contains variable names and values 78*1fa6dee9SAndroid Build Coastguard Worker// that are set within the build statement's scope in the Ninja file. 79*1fa6dee9SAndroid Build Coastguard Workertype BuildParams struct { 80*1fa6dee9SAndroid Build Coastguard Worker Comment string // The comment that will appear above the definition. 81*1fa6dee9SAndroid Build Coastguard Worker Depfile string // The dependency file name. 82*1fa6dee9SAndroid Build Coastguard Worker Deps Deps // The format of the dependency file. 83*1fa6dee9SAndroid Build Coastguard Worker Description string // The description that Ninja will print for the build. 84*1fa6dee9SAndroid Build Coastguard Worker Rule Rule // The rule to invoke. 85*1fa6dee9SAndroid Build Coastguard Worker Outputs []string // The list of explicit output targets. 86*1fa6dee9SAndroid Build Coastguard Worker ImplicitOutputs []string // The list of implicit output targets. 87*1fa6dee9SAndroid Build Coastguard Worker Inputs []string // The list of explicit input dependencies. 88*1fa6dee9SAndroid Build Coastguard Worker Implicits []string // The list of implicit input dependencies. 89*1fa6dee9SAndroid Build Coastguard Worker OrderOnly []string // The list of order-only dependencies. 90*1fa6dee9SAndroid Build Coastguard Worker Validations []string // The list of validations to run when this rule runs. 91*1fa6dee9SAndroid Build Coastguard Worker Args map[string]string // The variable/value pairs to set. 92*1fa6dee9SAndroid Build Coastguard Worker Optional bool // Skip outputting a default statement 93*1fa6dee9SAndroid Build Coastguard Worker} 94*1fa6dee9SAndroid Build Coastguard Worker 95*1fa6dee9SAndroid Build Coastguard Worker// A poolDef describes a pool definition. It does not include the name of the 96*1fa6dee9SAndroid Build Coastguard Worker// pool. 97*1fa6dee9SAndroid Build Coastguard Workertype poolDef struct { 98*1fa6dee9SAndroid Build Coastguard Worker Comment string 99*1fa6dee9SAndroid Build Coastguard Worker Depth int 100*1fa6dee9SAndroid Build Coastguard Worker} 101*1fa6dee9SAndroid Build Coastguard Worker 102*1fa6dee9SAndroid Build Coastguard Workerfunc parsePoolParams(scope scope, params *PoolParams) (*poolDef, 103*1fa6dee9SAndroid Build Coastguard Worker error) { 104*1fa6dee9SAndroid Build Coastguard Worker 105*1fa6dee9SAndroid Build Coastguard Worker def := &poolDef{ 106*1fa6dee9SAndroid Build Coastguard Worker Comment: params.Comment, 107*1fa6dee9SAndroid Build Coastguard Worker Depth: params.Depth, 108*1fa6dee9SAndroid Build Coastguard Worker } 109*1fa6dee9SAndroid Build Coastguard Worker 110*1fa6dee9SAndroid Build Coastguard Worker return def, nil 111*1fa6dee9SAndroid Build Coastguard Worker} 112*1fa6dee9SAndroid Build Coastguard Worker 113*1fa6dee9SAndroid Build Coastguard Workerfunc (p *poolDef) WriteTo(nw *ninjaWriter, name string) error { 114*1fa6dee9SAndroid Build Coastguard Worker if p.Comment != "" { 115*1fa6dee9SAndroid Build Coastguard Worker err := nw.Comment(p.Comment) 116*1fa6dee9SAndroid Build Coastguard Worker if err != nil { 117*1fa6dee9SAndroid Build Coastguard Worker return err 118*1fa6dee9SAndroid Build Coastguard Worker } 119*1fa6dee9SAndroid Build Coastguard Worker } 120*1fa6dee9SAndroid Build Coastguard Worker 121*1fa6dee9SAndroid Build Coastguard Worker err := nw.Pool(name) 122*1fa6dee9SAndroid Build Coastguard Worker if err != nil { 123*1fa6dee9SAndroid Build Coastguard Worker return err 124*1fa6dee9SAndroid Build Coastguard Worker } 125*1fa6dee9SAndroid Build Coastguard Worker 126*1fa6dee9SAndroid Build Coastguard Worker return nw.ScopedAssign("depth", strconv.Itoa(p.Depth)) 127*1fa6dee9SAndroid Build Coastguard Worker} 128*1fa6dee9SAndroid Build Coastguard Worker 129*1fa6dee9SAndroid Build Coastguard Worker// A ruleDef describes a rule definition. It does not include the name of the 130*1fa6dee9SAndroid Build Coastguard Worker// rule. 131*1fa6dee9SAndroid Build Coastguard Workertype ruleDef struct { 132*1fa6dee9SAndroid Build Coastguard Worker CommandDeps []*ninjaString 133*1fa6dee9SAndroid Build Coastguard Worker CommandOrderOnly []*ninjaString 134*1fa6dee9SAndroid Build Coastguard Worker Comment string 135*1fa6dee9SAndroid Build Coastguard Worker Pool Pool 136*1fa6dee9SAndroid Build Coastguard Worker Variables map[string]*ninjaString 137*1fa6dee9SAndroid Build Coastguard Worker} 138*1fa6dee9SAndroid Build Coastguard Worker 139*1fa6dee9SAndroid Build Coastguard Workerfunc parseRuleParams(scope scope, params *RuleParams) (*ruleDef, 140*1fa6dee9SAndroid Build Coastguard Worker error) { 141*1fa6dee9SAndroid Build Coastguard Worker 142*1fa6dee9SAndroid Build Coastguard Worker r := &ruleDef{ 143*1fa6dee9SAndroid Build Coastguard Worker Comment: params.Comment, 144*1fa6dee9SAndroid Build Coastguard Worker Pool: params.Pool, 145*1fa6dee9SAndroid Build Coastguard Worker Variables: make(map[string]*ninjaString), 146*1fa6dee9SAndroid Build Coastguard Worker } 147*1fa6dee9SAndroid Build Coastguard Worker 148*1fa6dee9SAndroid Build Coastguard Worker if params.Command == "" { 149*1fa6dee9SAndroid Build Coastguard Worker return nil, fmt.Errorf("encountered rule params with no command " + 150*1fa6dee9SAndroid Build Coastguard Worker "specified") 151*1fa6dee9SAndroid Build Coastguard Worker } 152*1fa6dee9SAndroid Build Coastguard Worker 153*1fa6dee9SAndroid Build Coastguard Worker if r.Pool != nil && !scope.IsPoolVisible(r.Pool) { 154*1fa6dee9SAndroid Build Coastguard Worker return nil, fmt.Errorf("Pool %s is not visible in this scope", r.Pool) 155*1fa6dee9SAndroid Build Coastguard Worker } 156*1fa6dee9SAndroid Build Coastguard Worker 157*1fa6dee9SAndroid Build Coastguard Worker value, err := parseNinjaString(scope, params.Command) 158*1fa6dee9SAndroid Build Coastguard Worker if err != nil { 159*1fa6dee9SAndroid Build Coastguard Worker return nil, fmt.Errorf("error parsing Command param: %s", err) 160*1fa6dee9SAndroid Build Coastguard Worker } 161*1fa6dee9SAndroid Build Coastguard Worker r.Variables["command"] = value 162*1fa6dee9SAndroid Build Coastguard Worker 163*1fa6dee9SAndroid Build Coastguard Worker if params.Depfile != "" { 164*1fa6dee9SAndroid Build Coastguard Worker value, err = parseNinjaString(scope, params.Depfile) 165*1fa6dee9SAndroid Build Coastguard Worker if err != nil { 166*1fa6dee9SAndroid Build Coastguard Worker return nil, fmt.Errorf("error parsing Depfile param: %s", err) 167*1fa6dee9SAndroid Build Coastguard Worker } 168*1fa6dee9SAndroid Build Coastguard Worker r.Variables["depfile"] = value 169*1fa6dee9SAndroid Build Coastguard Worker } 170*1fa6dee9SAndroid Build Coastguard Worker 171*1fa6dee9SAndroid Build Coastguard Worker if params.Deps != DepsNone { 172*1fa6dee9SAndroid Build Coastguard Worker r.Variables["deps"] = simpleNinjaString(params.Deps.String()) 173*1fa6dee9SAndroid Build Coastguard Worker } 174*1fa6dee9SAndroid Build Coastguard Worker 175*1fa6dee9SAndroid Build Coastguard Worker if params.Description != "" { 176*1fa6dee9SAndroid Build Coastguard Worker value, err = parseNinjaString(scope, params.Description) 177*1fa6dee9SAndroid Build Coastguard Worker if err != nil { 178*1fa6dee9SAndroid Build Coastguard Worker return nil, fmt.Errorf("error parsing Description param: %s", err) 179*1fa6dee9SAndroid Build Coastguard Worker } 180*1fa6dee9SAndroid Build Coastguard Worker r.Variables["description"] = value 181*1fa6dee9SAndroid Build Coastguard Worker } 182*1fa6dee9SAndroid Build Coastguard Worker 183*1fa6dee9SAndroid Build Coastguard Worker if params.Generator { 184*1fa6dee9SAndroid Build Coastguard Worker r.Variables["generator"] = simpleNinjaString("true") 185*1fa6dee9SAndroid Build Coastguard Worker } 186*1fa6dee9SAndroid Build Coastguard Worker 187*1fa6dee9SAndroid Build Coastguard Worker if params.Restat { 188*1fa6dee9SAndroid Build Coastguard Worker r.Variables["restat"] = simpleNinjaString("true") 189*1fa6dee9SAndroid Build Coastguard Worker } 190*1fa6dee9SAndroid Build Coastguard Worker 191*1fa6dee9SAndroid Build Coastguard Worker if params.Rspfile != "" { 192*1fa6dee9SAndroid Build Coastguard Worker value, err = parseNinjaString(scope, params.Rspfile) 193*1fa6dee9SAndroid Build Coastguard Worker if err != nil { 194*1fa6dee9SAndroid Build Coastguard Worker return nil, fmt.Errorf("error parsing Rspfile param: %s", err) 195*1fa6dee9SAndroid Build Coastguard Worker } 196*1fa6dee9SAndroid Build Coastguard Worker r.Variables["rspfile"] = value 197*1fa6dee9SAndroid Build Coastguard Worker } 198*1fa6dee9SAndroid Build Coastguard Worker 199*1fa6dee9SAndroid Build Coastguard Worker if params.RspfileContent != "" { 200*1fa6dee9SAndroid Build Coastguard Worker value, err = parseNinjaString(scope, params.RspfileContent) 201*1fa6dee9SAndroid Build Coastguard Worker if err != nil { 202*1fa6dee9SAndroid Build Coastguard Worker return nil, fmt.Errorf("error parsing RspfileContent param: %s", 203*1fa6dee9SAndroid Build Coastguard Worker err) 204*1fa6dee9SAndroid Build Coastguard Worker } 205*1fa6dee9SAndroid Build Coastguard Worker r.Variables["rspfile_content"] = value 206*1fa6dee9SAndroid Build Coastguard Worker } 207*1fa6dee9SAndroid Build Coastguard Worker 208*1fa6dee9SAndroid Build Coastguard Worker r.CommandDeps, err = parseNinjaStrings(scope, params.CommandDeps) 209*1fa6dee9SAndroid Build Coastguard Worker if err != nil { 210*1fa6dee9SAndroid Build Coastguard Worker return nil, fmt.Errorf("error parsing CommandDeps param: %s", err) 211*1fa6dee9SAndroid Build Coastguard Worker } 212*1fa6dee9SAndroid Build Coastguard Worker 213*1fa6dee9SAndroid Build Coastguard Worker r.CommandOrderOnly, err = parseNinjaStrings(scope, params.CommandOrderOnly) 214*1fa6dee9SAndroid Build Coastguard Worker if err != nil { 215*1fa6dee9SAndroid Build Coastguard Worker return nil, fmt.Errorf("error parsing CommandDeps param: %s", err) 216*1fa6dee9SAndroid Build Coastguard Worker } 217*1fa6dee9SAndroid Build Coastguard Worker 218*1fa6dee9SAndroid Build Coastguard Worker return r, nil 219*1fa6dee9SAndroid Build Coastguard Worker} 220*1fa6dee9SAndroid Build Coastguard Worker 221*1fa6dee9SAndroid Build Coastguard Workerfunc (r *ruleDef) WriteTo(nw *ninjaWriter, name string, nameTracker *nameTracker) error { 222*1fa6dee9SAndroid Build Coastguard Worker 223*1fa6dee9SAndroid Build Coastguard Worker if r.Comment != "" { 224*1fa6dee9SAndroid Build Coastguard Worker err := nw.Comment(r.Comment) 225*1fa6dee9SAndroid Build Coastguard Worker if err != nil { 226*1fa6dee9SAndroid Build Coastguard Worker return err 227*1fa6dee9SAndroid Build Coastguard Worker } 228*1fa6dee9SAndroid Build Coastguard Worker } 229*1fa6dee9SAndroid Build Coastguard Worker 230*1fa6dee9SAndroid Build Coastguard Worker err := nw.Rule(name) 231*1fa6dee9SAndroid Build Coastguard Worker if err != nil { 232*1fa6dee9SAndroid Build Coastguard Worker return err 233*1fa6dee9SAndroid Build Coastguard Worker } 234*1fa6dee9SAndroid Build Coastguard Worker 235*1fa6dee9SAndroid Build Coastguard Worker if r.Pool != nil { 236*1fa6dee9SAndroid Build Coastguard Worker err = nw.ScopedAssign("pool", nameTracker.Pool(r.Pool)) 237*1fa6dee9SAndroid Build Coastguard Worker if err != nil { 238*1fa6dee9SAndroid Build Coastguard Worker return err 239*1fa6dee9SAndroid Build Coastguard Worker } 240*1fa6dee9SAndroid Build Coastguard Worker } 241*1fa6dee9SAndroid Build Coastguard Worker 242*1fa6dee9SAndroid Build Coastguard Worker err = writeVariables(nw, r.Variables, nameTracker) 243*1fa6dee9SAndroid Build Coastguard Worker if err != nil { 244*1fa6dee9SAndroid Build Coastguard Worker return err 245*1fa6dee9SAndroid Build Coastguard Worker } 246*1fa6dee9SAndroid Build Coastguard Worker 247*1fa6dee9SAndroid Build Coastguard Worker return nil 248*1fa6dee9SAndroid Build Coastguard Worker} 249*1fa6dee9SAndroid Build Coastguard Worker 250*1fa6dee9SAndroid Build Coastguard Worker// A buildDef describes a build target definition. 251*1fa6dee9SAndroid Build Coastguard Workertype buildDef struct { 252*1fa6dee9SAndroid Build Coastguard Worker Comment string 253*1fa6dee9SAndroid Build Coastguard Worker Rule Rule 254*1fa6dee9SAndroid Build Coastguard Worker RuleDef *ruleDef 255*1fa6dee9SAndroid Build Coastguard Worker Outputs []*ninjaString 256*1fa6dee9SAndroid Build Coastguard Worker OutputStrings []string 257*1fa6dee9SAndroid Build Coastguard Worker ImplicitOutputs []*ninjaString 258*1fa6dee9SAndroid Build Coastguard Worker ImplicitOutputStrings []string 259*1fa6dee9SAndroid Build Coastguard Worker Inputs []*ninjaString 260*1fa6dee9SAndroid Build Coastguard Worker InputStrings []string 261*1fa6dee9SAndroid Build Coastguard Worker Implicits []*ninjaString 262*1fa6dee9SAndroid Build Coastguard Worker ImplicitStrings []string 263*1fa6dee9SAndroid Build Coastguard Worker OrderOnly []*ninjaString 264*1fa6dee9SAndroid Build Coastguard Worker OrderOnlyStrings []string 265*1fa6dee9SAndroid Build Coastguard Worker Validations []*ninjaString 266*1fa6dee9SAndroid Build Coastguard Worker ValidationStrings []string 267*1fa6dee9SAndroid Build Coastguard Worker Args map[Variable]*ninjaString 268*1fa6dee9SAndroid Build Coastguard Worker Variables map[string]*ninjaString 269*1fa6dee9SAndroid Build Coastguard Worker Optional bool 270*1fa6dee9SAndroid Build Coastguard Worker} 271*1fa6dee9SAndroid Build Coastguard Worker 272*1fa6dee9SAndroid Build Coastguard Workerfunc formatTags(tags map[string]string, rule Rule) string { 273*1fa6dee9SAndroid Build Coastguard Worker // Maps in golang do not have a guaranteed iteration order, nor is there an 274*1fa6dee9SAndroid Build Coastguard Worker // ordered map type in the stdlib, but we need to deterministically generate 275*1fa6dee9SAndroid Build Coastguard Worker // the ninja file. 276*1fa6dee9SAndroid Build Coastguard Worker keys := make([]string, 0, len(tags)) 277*1fa6dee9SAndroid Build Coastguard Worker for k := range tags { 278*1fa6dee9SAndroid Build Coastguard Worker keys = append(keys, k) 279*1fa6dee9SAndroid Build Coastguard Worker } 280*1fa6dee9SAndroid Build Coastguard Worker sort.Strings(keys) 281*1fa6dee9SAndroid Build Coastguard Worker pairs := make([]string, 0, len(keys)) 282*1fa6dee9SAndroid Build Coastguard Worker for _, k := range keys { 283*1fa6dee9SAndroid Build Coastguard Worker pairs = append(pairs, k+"="+tags[k]) 284*1fa6dee9SAndroid Build Coastguard Worker } 285*1fa6dee9SAndroid Build Coastguard Worker pairs = append(pairs, "rule_name="+rule.name()) 286*1fa6dee9SAndroid Build Coastguard Worker return strings.Join(pairs, ";") 287*1fa6dee9SAndroid Build Coastguard Worker} 288*1fa6dee9SAndroid Build Coastguard Worker 289*1fa6dee9SAndroid Build Coastguard Workerfunc parseBuildParams(scope scope, params *BuildParams, 290*1fa6dee9SAndroid Build Coastguard Worker tags map[string]string) (*buildDef, error) { 291*1fa6dee9SAndroid Build Coastguard Worker 292*1fa6dee9SAndroid Build Coastguard Worker comment := params.Comment 293*1fa6dee9SAndroid Build Coastguard Worker rule := params.Rule 294*1fa6dee9SAndroid Build Coastguard Worker 295*1fa6dee9SAndroid Build Coastguard Worker b := &buildDef{ 296*1fa6dee9SAndroid Build Coastguard Worker Comment: comment, 297*1fa6dee9SAndroid Build Coastguard Worker Rule: rule, 298*1fa6dee9SAndroid Build Coastguard Worker } 299*1fa6dee9SAndroid Build Coastguard Worker 300*1fa6dee9SAndroid Build Coastguard Worker setVariable := func(name string, value *ninjaString) { 301*1fa6dee9SAndroid Build Coastguard Worker if b.Variables == nil { 302*1fa6dee9SAndroid Build Coastguard Worker b.Variables = make(map[string]*ninjaString) 303*1fa6dee9SAndroid Build Coastguard Worker } 304*1fa6dee9SAndroid Build Coastguard Worker b.Variables[name] = value 305*1fa6dee9SAndroid Build Coastguard Worker } 306*1fa6dee9SAndroid Build Coastguard Worker 307*1fa6dee9SAndroid Build Coastguard Worker if !scope.IsRuleVisible(rule) { 308*1fa6dee9SAndroid Build Coastguard Worker return nil, fmt.Errorf("Rule %s is not visible in this scope", rule) 309*1fa6dee9SAndroid Build Coastguard Worker } 310*1fa6dee9SAndroid Build Coastguard Worker 311*1fa6dee9SAndroid Build Coastguard Worker if len(params.Outputs) == 0 { 312*1fa6dee9SAndroid Build Coastguard Worker return nil, errors.New("Outputs param has no elements") 313*1fa6dee9SAndroid Build Coastguard Worker } 314*1fa6dee9SAndroid Build Coastguard Worker 315*1fa6dee9SAndroid Build Coastguard Worker var err error 316*1fa6dee9SAndroid Build Coastguard Worker b.Outputs, b.OutputStrings, err = parseNinjaOrSimpleStrings(scope, params.Outputs) 317*1fa6dee9SAndroid Build Coastguard Worker if err != nil { 318*1fa6dee9SAndroid Build Coastguard Worker return nil, fmt.Errorf("error parsing Outputs param: %s", err) 319*1fa6dee9SAndroid Build Coastguard Worker } 320*1fa6dee9SAndroid Build Coastguard Worker 321*1fa6dee9SAndroid Build Coastguard Worker b.ImplicitOutputs, b.ImplicitOutputStrings, err = parseNinjaOrSimpleStrings(scope, params.ImplicitOutputs) 322*1fa6dee9SAndroid Build Coastguard Worker if err != nil { 323*1fa6dee9SAndroid Build Coastguard Worker return nil, fmt.Errorf("error parsing ImplicitOutputs param: %s", err) 324*1fa6dee9SAndroid Build Coastguard Worker } 325*1fa6dee9SAndroid Build Coastguard Worker 326*1fa6dee9SAndroid Build Coastguard Worker b.Inputs, b.InputStrings, err = parseNinjaOrSimpleStrings(scope, params.Inputs) 327*1fa6dee9SAndroid Build Coastguard Worker if err != nil { 328*1fa6dee9SAndroid Build Coastguard Worker return nil, fmt.Errorf("error parsing Inputs param: %s", err) 329*1fa6dee9SAndroid Build Coastguard Worker } 330*1fa6dee9SAndroid Build Coastguard Worker 331*1fa6dee9SAndroid Build Coastguard Worker b.Implicits, b.ImplicitStrings, err = parseNinjaOrSimpleStrings(scope, params.Implicits) 332*1fa6dee9SAndroid Build Coastguard Worker if err != nil { 333*1fa6dee9SAndroid Build Coastguard Worker return nil, fmt.Errorf("error parsing Implicits param: %s", err) 334*1fa6dee9SAndroid Build Coastguard Worker } 335*1fa6dee9SAndroid Build Coastguard Worker 336*1fa6dee9SAndroid Build Coastguard Worker b.OrderOnly, b.OrderOnlyStrings, err = parseNinjaOrSimpleStrings(scope, params.OrderOnly) 337*1fa6dee9SAndroid Build Coastguard Worker if err != nil { 338*1fa6dee9SAndroid Build Coastguard Worker return nil, fmt.Errorf("error parsing OrderOnly param: %s", err) 339*1fa6dee9SAndroid Build Coastguard Worker } 340*1fa6dee9SAndroid Build Coastguard Worker 341*1fa6dee9SAndroid Build Coastguard Worker b.Validations, b.ValidationStrings, err = parseNinjaOrSimpleStrings(scope, params.Validations) 342*1fa6dee9SAndroid Build Coastguard Worker if err != nil { 343*1fa6dee9SAndroid Build Coastguard Worker return nil, fmt.Errorf("error parsing Validations param: %s", err) 344*1fa6dee9SAndroid Build Coastguard Worker } 345*1fa6dee9SAndroid Build Coastguard Worker 346*1fa6dee9SAndroid Build Coastguard Worker b.Optional = params.Optional 347*1fa6dee9SAndroid Build Coastguard Worker 348*1fa6dee9SAndroid Build Coastguard Worker if params.Depfile != "" { 349*1fa6dee9SAndroid Build Coastguard Worker value, err := parseNinjaString(scope, params.Depfile) 350*1fa6dee9SAndroid Build Coastguard Worker if err != nil { 351*1fa6dee9SAndroid Build Coastguard Worker return nil, fmt.Errorf("error parsing Depfile param: %s", err) 352*1fa6dee9SAndroid Build Coastguard Worker } 353*1fa6dee9SAndroid Build Coastguard Worker setVariable("depfile", value) 354*1fa6dee9SAndroid Build Coastguard Worker } 355*1fa6dee9SAndroid Build Coastguard Worker 356*1fa6dee9SAndroid Build Coastguard Worker if params.Deps != DepsNone { 357*1fa6dee9SAndroid Build Coastguard Worker setVariable("deps", simpleNinjaString(params.Deps.String())) 358*1fa6dee9SAndroid Build Coastguard Worker } 359*1fa6dee9SAndroid Build Coastguard Worker 360*1fa6dee9SAndroid Build Coastguard Worker if params.Description != "" { 361*1fa6dee9SAndroid Build Coastguard Worker value, err := parseNinjaString(scope, params.Description) 362*1fa6dee9SAndroid Build Coastguard Worker if err != nil { 363*1fa6dee9SAndroid Build Coastguard Worker return nil, fmt.Errorf("error parsing Description param: %s", err) 364*1fa6dee9SAndroid Build Coastguard Worker } 365*1fa6dee9SAndroid Build Coastguard Worker setVariable("description", value) 366*1fa6dee9SAndroid Build Coastguard Worker } 367*1fa6dee9SAndroid Build Coastguard Worker 368*1fa6dee9SAndroid Build Coastguard Worker if len(tags) > 0 { 369*1fa6dee9SAndroid Build Coastguard Worker setVariable("tags", simpleNinjaString(formatTags(tags, rule))) 370*1fa6dee9SAndroid Build Coastguard Worker } 371*1fa6dee9SAndroid Build Coastguard Worker 372*1fa6dee9SAndroid Build Coastguard Worker argNameScope := rule.scope() 373*1fa6dee9SAndroid Build Coastguard Worker 374*1fa6dee9SAndroid Build Coastguard Worker if len(params.Args) > 0 { 375*1fa6dee9SAndroid Build Coastguard Worker b.Args = make(map[Variable]*ninjaString) 376*1fa6dee9SAndroid Build Coastguard Worker for name, value := range params.Args { 377*1fa6dee9SAndroid Build Coastguard Worker if !rule.isArg(name) { 378*1fa6dee9SAndroid Build Coastguard Worker return nil, fmt.Errorf("unknown argument %q", name) 379*1fa6dee9SAndroid Build Coastguard Worker } 380*1fa6dee9SAndroid Build Coastguard Worker 381*1fa6dee9SAndroid Build Coastguard Worker argVar, err := argNameScope.LookupVariable(name) 382*1fa6dee9SAndroid Build Coastguard Worker if err != nil { 383*1fa6dee9SAndroid Build Coastguard Worker // This shouldn't happen. 384*1fa6dee9SAndroid Build Coastguard Worker return nil, fmt.Errorf("argument lookup error: %s", err) 385*1fa6dee9SAndroid Build Coastguard Worker } 386*1fa6dee9SAndroid Build Coastguard Worker 387*1fa6dee9SAndroid Build Coastguard Worker ninjaValue, err := parseNinjaString(scope, value) 388*1fa6dee9SAndroid Build Coastguard Worker if err != nil { 389*1fa6dee9SAndroid Build Coastguard Worker return nil, fmt.Errorf("error parsing variable %q: %s", name, 390*1fa6dee9SAndroid Build Coastguard Worker err) 391*1fa6dee9SAndroid Build Coastguard Worker } 392*1fa6dee9SAndroid Build Coastguard Worker 393*1fa6dee9SAndroid Build Coastguard Worker b.Args[argVar] = ninjaValue 394*1fa6dee9SAndroid Build Coastguard Worker } 395*1fa6dee9SAndroid Build Coastguard Worker } 396*1fa6dee9SAndroid Build Coastguard Worker 397*1fa6dee9SAndroid Build Coastguard Worker return b, nil 398*1fa6dee9SAndroid Build Coastguard Worker} 399*1fa6dee9SAndroid Build Coastguard Worker 400*1fa6dee9SAndroid Build Coastguard Workerfunc (b *buildDef) WriteTo(nw *ninjaWriter, nameTracker *nameTracker) error { 401*1fa6dee9SAndroid Build Coastguard Worker var ( 402*1fa6dee9SAndroid Build Coastguard Worker comment = b.Comment 403*1fa6dee9SAndroid Build Coastguard Worker rule = nameTracker.Rule(b.Rule) 404*1fa6dee9SAndroid Build Coastguard Worker outputs = b.Outputs 405*1fa6dee9SAndroid Build Coastguard Worker implicitOuts = b.ImplicitOutputs 406*1fa6dee9SAndroid Build Coastguard Worker explicitDeps = b.Inputs 407*1fa6dee9SAndroid Build Coastguard Worker implicitDeps = b.Implicits 408*1fa6dee9SAndroid Build Coastguard Worker orderOnlyDeps = b.OrderOnly 409*1fa6dee9SAndroid Build Coastguard Worker validations = b.Validations 410*1fa6dee9SAndroid Build Coastguard Worker outputStrings = b.OutputStrings 411*1fa6dee9SAndroid Build Coastguard Worker implicitOutStrings = b.ImplicitOutputStrings 412*1fa6dee9SAndroid Build Coastguard Worker explicitDepStrings = b.InputStrings 413*1fa6dee9SAndroid Build Coastguard Worker implicitDepStrings = b.ImplicitStrings 414*1fa6dee9SAndroid Build Coastguard Worker orderOnlyDepStrings = b.OrderOnlyStrings 415*1fa6dee9SAndroid Build Coastguard Worker validationStrings = b.ValidationStrings 416*1fa6dee9SAndroid Build Coastguard Worker ) 417*1fa6dee9SAndroid Build Coastguard Worker 418*1fa6dee9SAndroid Build Coastguard Worker if b.RuleDef != nil { 419*1fa6dee9SAndroid Build Coastguard Worker implicitDeps = append(b.RuleDef.CommandDeps, implicitDeps...) 420*1fa6dee9SAndroid Build Coastguard Worker orderOnlyDeps = append(b.RuleDef.CommandOrderOnly, orderOnlyDeps...) 421*1fa6dee9SAndroid Build Coastguard Worker } 422*1fa6dee9SAndroid Build Coastguard Worker 423*1fa6dee9SAndroid Build Coastguard Worker err := nw.Build(comment, rule, outputs, implicitOuts, explicitDeps, implicitDeps, orderOnlyDeps, validations, 424*1fa6dee9SAndroid Build Coastguard Worker outputStrings, implicitOutStrings, explicitDepStrings, 425*1fa6dee9SAndroid Build Coastguard Worker implicitDepStrings, orderOnlyDepStrings, validationStrings, 426*1fa6dee9SAndroid Build Coastguard Worker nameTracker) 427*1fa6dee9SAndroid Build Coastguard Worker if err != nil { 428*1fa6dee9SAndroid Build Coastguard Worker return err 429*1fa6dee9SAndroid Build Coastguard Worker } 430*1fa6dee9SAndroid Build Coastguard Worker 431*1fa6dee9SAndroid Build Coastguard Worker err = writeVariables(nw, b.Variables, nameTracker) 432*1fa6dee9SAndroid Build Coastguard Worker if err != nil { 433*1fa6dee9SAndroid Build Coastguard Worker return err 434*1fa6dee9SAndroid Build Coastguard Worker } 435*1fa6dee9SAndroid Build Coastguard Worker 436*1fa6dee9SAndroid Build Coastguard Worker type nameValuePair struct { 437*1fa6dee9SAndroid Build Coastguard Worker name, value string 438*1fa6dee9SAndroid Build Coastguard Worker } 439*1fa6dee9SAndroid Build Coastguard Worker 440*1fa6dee9SAndroid Build Coastguard Worker args := make([]nameValuePair, 0, len(b.Args)) 441*1fa6dee9SAndroid Build Coastguard Worker 442*1fa6dee9SAndroid Build Coastguard Worker for argVar, value := range b.Args { 443*1fa6dee9SAndroid Build Coastguard Worker fullName := nameTracker.Variable(argVar) 444*1fa6dee9SAndroid Build Coastguard Worker args = append(args, nameValuePair{fullName, value.Value(nameTracker)}) 445*1fa6dee9SAndroid Build Coastguard Worker } 446*1fa6dee9SAndroid Build Coastguard Worker sort.Slice(args, func(i, j int) bool { return args[i].name < args[j].name }) 447*1fa6dee9SAndroid Build Coastguard Worker 448*1fa6dee9SAndroid Build Coastguard Worker for _, pair := range args { 449*1fa6dee9SAndroid Build Coastguard Worker err = nw.ScopedAssign(pair.name, pair.value) 450*1fa6dee9SAndroid Build Coastguard Worker if err != nil { 451*1fa6dee9SAndroid Build Coastguard Worker return err 452*1fa6dee9SAndroid Build Coastguard Worker } 453*1fa6dee9SAndroid Build Coastguard Worker } 454*1fa6dee9SAndroid Build Coastguard Worker 455*1fa6dee9SAndroid Build Coastguard Worker if !b.Optional { 456*1fa6dee9SAndroid Build Coastguard Worker err = nw.Default(nameTracker, outputs, outputStrings) 457*1fa6dee9SAndroid Build Coastguard Worker if err != nil { 458*1fa6dee9SAndroid Build Coastguard Worker return err 459*1fa6dee9SAndroid Build Coastguard Worker } 460*1fa6dee9SAndroid Build Coastguard Worker } 461*1fa6dee9SAndroid Build Coastguard Worker 462*1fa6dee9SAndroid Build Coastguard Worker return nw.BlankLine() 463*1fa6dee9SAndroid Build Coastguard Worker} 464*1fa6dee9SAndroid Build Coastguard Worker 465*1fa6dee9SAndroid Build Coastguard Workerfunc writeVariables(nw *ninjaWriter, variables map[string]*ninjaString, nameTracker *nameTracker) error { 466*1fa6dee9SAndroid Build Coastguard Worker var keys []string 467*1fa6dee9SAndroid Build Coastguard Worker for k := range variables { 468*1fa6dee9SAndroid Build Coastguard Worker keys = append(keys, k) 469*1fa6dee9SAndroid Build Coastguard Worker } 470*1fa6dee9SAndroid Build Coastguard Worker sort.Strings(keys) 471*1fa6dee9SAndroid Build Coastguard Worker 472*1fa6dee9SAndroid Build Coastguard Worker for _, name := range keys { 473*1fa6dee9SAndroid Build Coastguard Worker err := nw.ScopedAssign(name, variables[name].Value(nameTracker)) 474*1fa6dee9SAndroid Build Coastguard Worker if err != nil { 475*1fa6dee9SAndroid Build Coastguard Worker return err 476*1fa6dee9SAndroid Build Coastguard Worker } 477*1fa6dee9SAndroid Build Coastguard Worker } 478*1fa6dee9SAndroid Build Coastguard Worker return nil 479*1fa6dee9SAndroid Build Coastguard Worker} 480