xref: /aosp_15_r20/build/blueprint/ninja_defs.go (revision 1fa6dee971e1612fa5cc0aa5ca2d35a22e2c34a3)
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