blob: 3edd24346ea306c1571e4f9d9823ed738c952ebd [file] [log] [blame]
Andres Moralesda8706f2015-04-29 12:46:49 -07001package main
2
3import (
Colin Crossb0931242015-06-29 14:18:27 -07004 "bytes"
Andres Morales8ae47de2015-05-11 12:26:07 -07005 "errors"
Andres Moralesda8706f2015-04-29 12:46:49 -07006 "fmt"
Colin Crossb0931242015-06-29 14:18:27 -07007 "io"
Andres Moralesda8706f2015-04-29 12:46:49 -07008 "os"
9 "path"
Andres Morales8ae47de2015-05-11 12:26:07 -070010 "path/filepath"
Andres Moralesaf11df12015-04-30 12:14:34 -070011 "regexp"
Andres Moralesda8706f2015-04-29 12:46:49 -070012 "strings"
Colin Crossb1a66c02015-06-29 16:24:57 -070013 "text/scanner"
Andres Moralesda8706f2015-04-29 12:46:49 -070014
Colin Crossb3245e92015-06-30 16:27:57 -070015 "github.com/google/blueprint"
Andres Moralesda8706f2015-04-29 12:46:49 -070016 bpparser "github.com/google/blueprint/parser"
17)
18
Andres Morales8ae47de2015-05-11 12:26:07 -070019var recursiveSubdirRegex *regexp.Regexp = regexp.MustCompile("(.+)/\\*\\*/(.+)")
20
Andres Moralesda8706f2015-04-29 12:46:49 -070021type androidMkWriter struct {
Colin Crossb0931242015-06-29 14:18:27 -070022 io.Writer
Andres Moralesda8706f2015-04-29 12:46:49 -070023
Andres Moralesaf11df12015-04-30 12:14:34 -070024 blueprint *bpparser.File
25 path string
Andres Moralesda8706f2015-04-29 12:46:49 -070026}
27
Colin Cross3cc00f12015-07-07 12:22:51 -070028type propAssignment struct {
29 name, assigner, value string
30}
31
32func (a propAssignment) assignmentWithSuffix(suffix string) string {
33 if suffix != "" {
34 a.name = a.name + "_" + suffix
35 }
36 return a.name + " " + a.assigner + " " + a.value
37}
38
39func (a propAssignment) assignment() string {
40 return a.assignmentWithSuffix("")
41}
42
Colin Crossb0931242015-06-29 14:18:27 -070043func (w *androidMkWriter) WriteString(s string) (int, error) {
44 return io.WriteString(w.Writer, s)
45}
46
47func valueToString(value bpparser.Value) (string, error) {
Colin Crossb3245e92015-06-30 16:27:57 -070048 switch value.Type {
49 case bpparser.Bool:
50 return fmt.Sprintf("%t", value.BoolValue), nil
51 case bpparser.String:
52 return fmt.Sprintf("%s", processWildcards(value.StringValue)), nil
53 case bpparser.List:
54 val, err := listToMkString(value.ListValue)
Colin Crossb0931242015-06-29 14:18:27 -070055 if err != nil {
56 return "", err
57 }
Colin Crossb3245e92015-06-30 16:27:57 -070058 return fmt.Sprintf("\\\n%s", val), nil
59 case bpparser.Map:
60 return "", fmt.Errorf("Can't convert map to string")
61 default:
62 return "", fmt.Errorf("ERROR: unsupported type %d", value.Type)
Andres Moralesda8706f2015-04-29 12:46:49 -070063 }
Andres Moralesda8706f2015-04-29 12:46:49 -070064}
65
Dan Willemsen27012122015-06-26 17:40:54 -070066func appendValueToValue(dest bpparser.Value, src bpparser.Value) (bpparser.Value, error) {
67 if src.Type != dest.Type {
68 return bpparser.Value{}, fmt.Errorf("ERROR: source and destination types don't match")
69 }
70 switch dest.Type {
71 case bpparser.List:
72 dest.ListValue = append(dest.ListValue, src.ListValue...)
73 return dest, nil
74 case bpparser.String:
75 dest.StringValue += src.StringValue
76 return dest, nil
77 default:
78 return bpparser.Value{}, fmt.Errorf("ERROR: unsupported append with type %s", dest.Type.String())
79 }
80}
81
Andres Morales8ae47de2015-05-11 12:26:07 -070082func getTopOfAndroidTree(wd string) (string, error) {
83 if !filepath.IsAbs(wd) {
84 return "", errors.New("path must be absolute: " + wd)
85 }
86
87 topfile := "build/soong/bootstrap.bash"
88
89 for "/" != wd {
90 expected := filepath.Join(wd, topfile)
91
92 if _, err := os.Stat(expected); err == nil {
93 // Found the top
94 return wd, nil
95 }
96
97 wd = filepath.Join(wd, "..")
98 }
99
100 return "", errors.New("couldn't find top of tree from " + wd)
101}
102
Andres Moralesaf11df12015-04-30 12:14:34 -0700103// TODO: handle non-recursive wildcards?
104func processWildcards(s string) string {
Andres Morales8ae47de2015-05-11 12:26:07 -0700105 submatches := recursiveSubdirRegex.FindStringSubmatch(s)
106 if len(submatches) > 2 {
Andres Moralesaf11df12015-04-30 12:14:34 -0700107 // Found a wildcard rule
108 return fmt.Sprintf("$(call find-files-in-subdirs, $(LOCAL_PATH), %s, %s)",
Andres Morales8ae47de2015-05-11 12:26:07 -0700109 submatches[2], submatches[1])
Andres Moralesaf11df12015-04-30 12:14:34 -0700110 }
111
112 return s
113}
114
Colin Crossb0931242015-06-29 14:18:27 -0700115func listToMkString(list []bpparser.Value) (string, error) {
Andres Moralesda8706f2015-04-29 12:46:49 -0700116 lines := make([]string, 0, len(list))
117 for _, tok := range list {
Colin Crossb0931242015-06-29 14:18:27 -0700118 val, err := valueToString(tok)
119 if err != nil {
120 return "", err
121 }
122 lines = append(lines, fmt.Sprintf(" %s", val))
Andres Moralesda8706f2015-04-29 12:46:49 -0700123 }
124
Colin Crossb0931242015-06-29 14:18:27 -0700125 return strings.Join(lines, " \\\n"), nil
Andres Moralesda8706f2015-04-29 12:46:49 -0700126}
127
Andres Moralesaf11df12015-04-30 12:14:34 -0700128func translateTargetConditionals(props []*bpparser.Property,
Colin Crossb0931242015-06-29 14:18:27 -0700129 disabledBuilds map[string]bool, isHostRule bool) (computedProps []string, err error) {
Andres Moralesaf11df12015-04-30 12:14:34 -0700130 for _, target := range props {
131 conditionals := targetScopedPropertyConditionals
Dan Willemsen68fdfcc2015-06-11 14:05:01 -0700132 altConditionals := hostScopedPropertyConditionals
Andres Moralesaf11df12015-04-30 12:14:34 -0700133 if isHostRule {
Dan Willemsen68fdfcc2015-06-11 14:05:01 -0700134 conditionals, altConditionals = altConditionals, conditionals
Andres Moralesaf11df12015-04-30 12:14:34 -0700135 }
136
137 conditional, ok := conditionals[target.Name.Name]
138 if !ok {
Dan Willemsen68fdfcc2015-06-11 14:05:01 -0700139 if _, ok := altConditionals[target.Name.Name]; ok {
140 // This is only for the other build type
141 continue
142 } else {
Colin Crossb0931242015-06-29 14:18:27 -0700143 return nil, fmt.Errorf("Unsupported conditional %q", target.Name.Name)
Dan Willemsen68fdfcc2015-06-11 14:05:01 -0700144 }
Andres Moralesaf11df12015-04-30 12:14:34 -0700145 }
146
147 var scopedProps []string
148 for _, targetScopedProp := range target.Value.MapValue {
Colin Cross3cc00f12015-07-07 12:22:51 -0700149 if assignment, ok, err := translateSingleProperty(targetScopedProp); err != nil {
150 return nil, err
151 } else if ok {
152 scopedProps = append(scopedProps, assignment.assignment())
Andres Moralesaf11df12015-04-30 12:14:34 -0700153 } else if "disabled" == targetScopedProp.Name.Name {
154 if targetScopedProp.Value.BoolValue {
155 disabledBuilds[target.Name.Name] = true
156 } else {
157 delete(disabledBuilds, target.Name.Name)
158 }
Colin Crossb0931242015-06-29 14:18:27 -0700159 } else {
160 return nil, fmt.Errorf("Unsupported target property %q", targetScopedProp.Name.Name)
Andres Moralesaf11df12015-04-30 12:14:34 -0700161 }
162 }
163
164 if len(scopedProps) > 0 {
Dan Willemsen68fdfcc2015-06-11 14:05:01 -0700165 if conditional != "" {
166 computedProps = append(computedProps, conditional)
167 computedProps = append(computedProps, scopedProps...)
168 computedProps = append(computedProps, "endif")
169 } else {
170 computedProps = append(computedProps, scopedProps...)
171 }
Andres Moralesaf11df12015-04-30 12:14:34 -0700172 }
Andres Moralesda8706f2015-04-29 12:46:49 -0700173 }
Andres Moralesaf11df12015-04-30 12:14:34 -0700174
175 return
176}
177
Colin Cross7f64b6d2015-07-09 13:57:48 -0700178func translateProductVariableConditionals(props []*bpparser.Property) (computedProps []string, err error) {
179 for _, productVariable := range props {
180 v, ok := productVariableConditionals[productVariable.Name.Name]
181 if !ok {
182 return nil, fmt.Errorf("Unsupported product variable %q", productVariable.Name.Name)
183 }
184
185 var scopedProps []string
186 for _, conditionalScopedProp := range productVariable.Value.MapValue {
187 if assignment, ok, err := translateSingleProperty(conditionalScopedProp); err != nil {
188 return nil, err
189 } else if ok {
190 assignment.assigner = "+="
191 a := assignment.assignment()
192 if v.value != "" && strings.Contains(a, "%d") {
193 a = strings.Replace(a, "%d", v.value, 1)
194 }
195 scopedProps = append(scopedProps, a)
196 } else {
197 return nil, fmt.Errorf("Unsupported product variable property %q",
198 conditionalScopedProp.Name.Name)
199 }
200 }
201
202 if len(scopedProps) > 0 {
203 if v.conditional != "" {
204 computedProps = append(computedProps, v.conditional)
205 computedProps = append(computedProps, scopedProps...)
206 computedProps = append(computedProps, "endif")
207 } else {
208 computedProps = append(computedProps, scopedProps...)
209 }
210 }
211 }
212
213 return computedProps, nil
214}
215
Colin Crossec193632015-07-06 17:49:43 -0700216var secondTargetReplacer = strings.NewReplacer("TARGET_", "TARGET_2ND_")
217
Andres Moralesaf11df12015-04-30 12:14:34 -0700218func translateSuffixProperties(suffixProps []*bpparser.Property,
Colin Crossb0931242015-06-29 14:18:27 -0700219 suffixMap map[string]string) (computedProps []string, err error) {
Andres Moralesaf11df12015-04-30 12:14:34 -0700220 for _, suffixProp := range suffixProps {
221 if suffix, ok := suffixMap[suffixProp.Name.Name]; ok {
222 for _, stdProp := range suffixProp.Value.MapValue {
Colin Cross3cc00f12015-07-07 12:22:51 -0700223 if assignment, ok, err := translateSingleProperty(stdProp); err != nil {
224 return nil, err
225 } else if ok {
226 computedProps = append(computedProps, assignment.assignmentWithSuffix(suffix))
Andres Moralesaf11df12015-04-30 12:14:34 -0700227 } else {
Colin Crossb0931242015-06-29 14:18:27 -0700228 return nil, fmt.Errorf("Unsupported property %q", stdProp.Name.Name)
Andres Moralesaf11df12015-04-30 12:14:34 -0700229 }
230 }
Colin Crossec193632015-07-06 17:49:43 -0700231 } else if variant, ok := cpuVariantConditionals[suffixProp.Name.Name]; ok {
232 var conditionalProps []propAssignment
233 for _, stdProp := range suffixProp.Value.MapValue {
234 if assignment, ok, err := translateSingleProperty(stdProp); err != nil {
235 return nil, err
236 } else if ok {
237 conditionalProps = append(conditionalProps, assignment)
238 } else {
239 return nil, fmt.Errorf("Unsupported property %q", stdProp.Name.Name)
240 }
241 }
242
243 appendComputedProps := func() {
244 computedProps = append(computedProps, variant.conditional)
245 for _, prop := range conditionalProps {
246 prop.assigner = "+="
247 computedProps = append(computedProps, prop.assignmentWithSuffix(variant.suffix))
248 }
249 computedProps = append(computedProps, "endif")
250 }
251
252 appendComputedProps()
253 if variant.secondArch {
254 variant.conditional = secondTargetReplacer.Replace(variant.conditional)
255 variant.suffix = secondTargetReplacer.Replace(variant.suffix)
256 appendComputedProps()
257 }
Colin Crossb0931242015-06-29 14:18:27 -0700258 } else {
259 return nil, fmt.Errorf("Unsupported suffix property %q", suffixProp.Name.Name)
Andres Moralesaf11df12015-04-30 12:14:34 -0700260 }
261 }
262 return
263}
264
Colin Cross3cc00f12015-07-07 12:22:51 -0700265func translateSingleProperty(prop *bpparser.Property) (propAssignment, bool, error) {
266 var assignment propAssignment
267 if mkProp, ok := standardProperties[prop.Name.Name]; ok {
268 name := mkProp.string
269 val, err := valueToString(prop.Value)
270 if err != nil {
271 return propAssignment{}, false, err
272 }
273 assignment = propAssignment{name, ":=", val}
274 } else if rwProp, ok := rewriteProperties[prop.Name.Name]; ok {
275 val, err := valueToString(prop.Value)
276 if err != nil {
277 return propAssignment{}, false, err
278 }
279 assignment, err = rwProp.f(rwProp.string, prop, val)
280 if err != nil {
281 return propAssignment{}, false, err
282 }
283 } else {
284 // Unhandled, return false with no error to tell the caller to handle it
285 return propAssignment{}, false, nil
Colin Crossc41f6302015-06-30 12:19:47 -0700286 }
Colin Cross3cc00f12015-07-07 12:22:51 -0700287 return assignment, true, nil
Colin Crossc41f6302015-06-30 12:19:47 -0700288}
289
Colin Cross3cc00f12015-07-07 12:22:51 -0700290func appendAssign(name string, prop *bpparser.Property, val string) (propAssignment, error) {
291 return propAssignment{name, "+=", val}, nil
Dan Willemsen57ad08c2015-06-10 16:20:14 -0700292}
293
Colin Cross3cc00f12015-07-07 12:22:51 -0700294func prependLocalPath(name string, prop *bpparser.Property, val string) (propAssignment, error) {
295 return propAssignment{name, "+=", fmt.Sprintf("$(addprefix $(LOCAL_PATH)/,%s)", val)}, nil
Dan Willemsen1d9f2792015-06-22 15:40:14 -0700296}
297
Colin Cross3cc00f12015-07-07 12:22:51 -0700298func prependLocalModule(name string, prop *bpparser.Property, val string) (propAssignment, error) {
299 return propAssignment{name, ":=", "$(LOCAL_MODULE)" + val}, nil
300}
301
302func versionScript(name string, prop *bpparser.Property, val string) (propAssignment, error) {
303 return propAssignment{name, "+=", "-Wl,--version-script,$(LOCAL_PATH)/" + val}, nil
Colin Crossaee540a2015-07-06 17:48:31 -0700304}
305
Andres Moralesaf11df12015-04-30 12:14:34 -0700306func (w *androidMkWriter) writeModule(moduleRule string, props []string,
307 disabledBuilds map[string]bool, isHostRule bool) {
308 disabledConditionals := disabledTargetConditionals
309 if isHostRule {
310 disabledConditionals = disabledHostConditionals
311 }
312 for build, _ := range disabledBuilds {
313 if conditional, ok := disabledConditionals[build]; ok {
314 fmt.Fprintf(w, "%s\n", conditional)
315 defer fmt.Fprintf(w, "endif\n")
Andres Moralesda8706f2015-04-29 12:46:49 -0700316 }
Andres Moralesaf11df12015-04-30 12:14:34 -0700317 }
Andres Moralesda8706f2015-04-29 12:46:49 -0700318
Andres Moralesaf11df12015-04-30 12:14:34 -0700319 fmt.Fprintf(w, "include $(CLEAR_VARS)\n")
320 fmt.Fprintf(w, "%s\n", strings.Join(props, "\n"))
321 fmt.Fprintf(w, "include $(%s)\n\n", moduleRule)
322}
Andres Moralesda8706f2015-04-29 12:46:49 -0700323
Colin Crossb0931242015-06-29 14:18:27 -0700324func (w *androidMkWriter) parsePropsAndWriteModule(module *Module) error {
Dan Willemsen3a4045d2015-06-24 15:37:17 -0700325 standardProps := make([]string, 0, len(module.bpmod.Properties))
Andres Moralesaf11df12015-04-30 12:14:34 -0700326 disabledBuilds := make(map[string]bool)
Dan Willemsen3a4045d2015-06-24 15:37:17 -0700327 for _, prop := range module.bpmod.Properties {
Colin Cross3cc00f12015-07-07 12:22:51 -0700328 if assignment, ok, err := translateSingleProperty(prop); err != nil {
329 return err
330 } else if ok {
331 standardProps = append(standardProps, assignment.assignment())
Andres Moralesaf11df12015-04-30 12:14:34 -0700332 } else if suffixMap, ok := suffixProperties[prop.Name.Name]; ok {
Colin Crossb3245e92015-06-30 16:27:57 -0700333 props, err := translateSuffixProperties(prop.Value.MapValue, suffixMap)
Colin Crossb0931242015-06-29 14:18:27 -0700334 if err != nil {
335 return err
336 }
337 standardProps = append(standardProps, props...)
Andres Moralesaf11df12015-04-30 12:14:34 -0700338 } else if "target" == prop.Name.Name {
Colin Crossb3245e92015-06-30 16:27:57 -0700339 props, err := translateTargetConditionals(prop.Value.MapValue, disabledBuilds, module.isHostRule)
Colin Crossb0931242015-06-29 14:18:27 -0700340 if err != nil {
341 return err
342 }
343 standardProps = append(standardProps, props...)
Colin Cross7f64b6d2015-07-09 13:57:48 -0700344 } else if "product_variables" == prop.Name.Name {
345 props, err := translateProductVariableConditionals(prop.Value.MapValue)
346 if err != nil {
347 return err
348 }
349 standardProps = append(standardProps, props...)
Dan Willemsen0a544692015-06-24 15:50:07 -0700350 } else if _, ok := ignoredProperties[prop.Name.Name]; ok {
Andres Moralesaf11df12015-04-30 12:14:34 -0700351 } else {
Colin Crossb0931242015-06-29 14:18:27 -0700352 return fmt.Errorf("Unsupported property %q", prop.Name.Name)
Andres Moralesaf11df12015-04-30 12:14:34 -0700353 }
354 }
355
Dan Willemsen3a4045d2015-06-24 15:37:17 -0700356 w.writeModule(module.mkname, standardProps, disabledBuilds, module.isHostRule)
Colin Crossb0931242015-06-29 14:18:27 -0700357
358 return nil
Dan Willemsen68fdfcc2015-06-11 14:05:01 -0700359}
360
Dan Willemsen26173162015-07-06 13:36:50 -0700361func canUseWholeStaticLibrary(m *Module) (bool, error) {
362 ret := true
363
364 isCompatible := func(props Properties, prop *bpparser.Property) error {
365 for _, p := range prop.Value.MapValue {
366 if p.Name.Name == "cflags" {
367 ret = false
368 return nil
369 }
370 if prop.Name.Name == "static" {
371 if p.Name.Name == "srcs" {
372 ret = false
373 return nil
374 }
375 }
376 }
377 return nil
378 }
379
380 err := m.IterateArchPropertiesWithName("shared", isCompatible)
381 if err != nil {
382 return false, err
383 }
384 err = m.IterateArchPropertiesWithName("static", isCompatible)
385 if err != nil {
386 return false, err
387 }
388
389 return ret, nil
390}
391
Colin Crossb0931242015-06-29 14:18:27 -0700392func (w *androidMkWriter) mutateModule(module *Module) (modules []*Module, err error) {
Dan Willemsen3a4045d2015-06-24 15:37:17 -0700393 modules = []*Module{module}
Dan Willemsen49f50452015-06-24 14:56:00 -0700394
Dan Willemsen3a4045d2015-06-24 15:37:17 -0700395 if module.bpname == "cc_library" {
396 modules = []*Module{
397 newModule(module.bpmod),
398 newModule(module.bpmod),
399 }
Dan Willemsen27012122015-06-26 17:40:54 -0700400
401 ccLinkageCopy := func(props Properties, prop *bpparser.Property) error {
402 for _, p := range prop.Value.MapValue {
403 err := props.AppendToProp(p.Name.Name, p)
404 if err != nil {
405 return err
406 }
407 }
408 props.DeleteProp(prop.Name.Name)
409 return nil
410 }
Dan Willemsen26173162015-07-06 13:36:50 -0700411 deleteProp := func(props Properties, prop *bpparser.Property) error {
Dan Willemsen27012122015-06-26 17:40:54 -0700412 props.DeleteProp(prop.Name.Name)
413 return nil
414 }
415
Dan Willemsen26173162015-07-06 13:36:50 -0700416 if ok, err := canUseWholeStaticLibrary(module); err != nil {
417 return nil, err
418 } else if ok {
419 err = modules[0].IterateArchPropertiesWithName("srcs", deleteProp)
420 if err != nil {
421 return nil, err
422 }
423
424 if nameProp, ok := modules[0].Properties().Prop("name"); !ok {
425 return nil, fmt.Errorf("Can't find name property")
426 } else {
427 modules[0].Properties().AppendToProp("whole_static_libs", &bpparser.Property{
428 Value: bpparser.Value{
429 Type: bpparser.List,
430 ListValue: []bpparser.Value{
431 nameProp.Value.Copy(),
432 },
433 },
434 })
435 }
436 }
437
Dan Willemsen3a4045d2015-06-24 15:37:17 -0700438 modules[0].bpname = "cc_library_shared"
Dan Willemsen27012122015-06-26 17:40:54 -0700439 err := modules[0].IterateArchPropertiesWithName("shared", ccLinkageCopy)
440 if err != nil {
441 return nil, err
442 }
Dan Willemsen26173162015-07-06 13:36:50 -0700443 err = modules[0].IterateArchPropertiesWithName("static", deleteProp)
Dan Willemsen27012122015-06-26 17:40:54 -0700444 if err != nil {
445 return nil, err
446 }
447
Dan Willemsen3a4045d2015-06-24 15:37:17 -0700448 modules[1].bpname = "cc_library_static"
Dan Willemsen26173162015-07-06 13:36:50 -0700449 err = modules[1].IterateArchPropertiesWithName("shared", deleteProp)
Dan Willemsen27012122015-06-26 17:40:54 -0700450 if err != nil {
451 return nil, err
452 }
453 err = modules[1].IterateArchPropertiesWithName("static", ccLinkageCopy)
454 if err != nil {
455 return nil, err
456 }
Dan Willemsen3a4045d2015-06-24 15:37:17 -0700457 }
458
459 for _, mod := range modules {
Colin Crossb0931242015-06-29 14:18:27 -0700460 err := mod.translateRuleName()
461 if err != nil {
462 return nil, err
463 }
Dan Willemsen27012122015-06-26 17:40:54 -0700464 if mod.isHostRule || !mod.PropBool("host_supported") {
Dan Willemsen3a4045d2015-06-24 15:37:17 -0700465 continue
466 }
467
468 m := &Module{
469 bpmod: mod.bpmod,
470 bpname: mod.bpname,
471 isHostRule: true,
472 }
Colin Crossb0931242015-06-29 14:18:27 -0700473 err = m.translateRuleName()
474 if err != nil {
475 return nil, err
476 }
Dan Willemsen3a4045d2015-06-24 15:37:17 -0700477 modules = append(modules, m)
Dan Willemsen68fdfcc2015-06-11 14:05:01 -0700478 }
479
Dan Willemsen49f50452015-06-24 14:56:00 -0700480 return
481}
Dan Willemsen68fdfcc2015-06-11 14:05:01 -0700482
Colin Crossb0931242015-06-29 14:18:27 -0700483func (w *androidMkWriter) handleModule(inputModule *bpparser.Module) error {
Colin Crossb1a66c02015-06-29 16:24:57 -0700484 comment := w.getCommentBlock(inputModule.Type.Pos)
485 if translation, translated, err := getCommentTranslation(comment); err != nil {
486 return err
487 } else if translated {
488 w.WriteString(translation)
489 return nil
490 }
491
Colin Cross70a5f072015-06-29 17:44:56 -0700492 if ignoredModuleType[inputModule.Type.Name] {
493 return nil
494 }
495
Colin Crossb0931242015-06-29 14:18:27 -0700496 modules, err := w.mutateModule(newModule(inputModule))
497 if err != nil {
498 return err
499 }
Dan Willemsen49f50452015-06-24 14:56:00 -0700500
501 for _, module := range modules {
Colin Crossb0931242015-06-29 14:18:27 -0700502 err := w.parsePropsAndWriteModule(module)
503 if err != nil {
504 return err
505 }
Andres Moralesaf11df12015-04-30 12:14:34 -0700506 }
Colin Crossb0931242015-06-29 14:18:27 -0700507
508 return nil
Andres Moralesaf11df12015-04-30 12:14:34 -0700509}
510
511func (w *androidMkWriter) handleSubdirs(value bpparser.Value) {
Andres Morales8ae47de2015-05-11 12:26:07 -0700512 subdirs := make([]string, 0, len(value.ListValue))
513 for _, tok := range value.ListValue {
514 subdirs = append(subdirs, tok.StringValue)
Andres Moralesda8706f2015-04-29 12:46:49 -0700515 }
Ying Wang38284902015-06-02 18:44:59 -0700516 // The current makefile may be generated to outside the source tree (such as the out directory), with a different structure.
517 fmt.Fprintf(w, "# Uncomment the following line if you really want to include subdir Android.mks.\n")
518 fmt.Fprintf(w, "# include $(wildcard $(addsuffix $(LOCAL_PATH)/%s/, Android.mk))\n", strings.Join(subdirs, " "))
Andres Moralesda8706f2015-04-29 12:46:49 -0700519}
520
Andres Morales8ae47de2015-05-11 12:26:07 -0700521func (w *androidMkWriter) handleLocalPath() error {
Colin Crossb3245e92015-06-30 16:27:57 -0700522 w.WriteString("LOCAL_PATH := " + w.path + "\n")
Dan Willemsenc2666e62015-06-10 16:18:58 -0700523 w.WriteString("LOCAL_MODULE_MAKEFILE := $(lastword $(MAKEFILE_LIST))\n\n")
Andres Morales8ae47de2015-05-11 12:26:07 -0700524 return nil
525}
526
Colin Crossb1a66c02015-06-29 16:24:57 -0700527// Returns any block comment on the line preceding pos as a string
528func (w *androidMkWriter) getCommentBlock(pos scanner.Position) string {
529 var buf []byte
530
531 comments := w.blueprint.Comments
532 for i, c := range comments {
533 if c.EndLine() == pos.Line-1 {
534 line := pos.Line
535 for j := i; j >= 0; j-- {
536 c = comments[j]
537 if c.EndLine() == line-1 {
538 buf = append([]byte(c.Text()), buf...)
539 line = c.Pos.Line
540 } else {
541 break
542 }
543 }
544 }
545 }
546
547 return string(buf)
548}
549
550func getCommentTranslation(comment string) (string, bool, error) {
551 lines := strings.Split(comment, "\n")
552
553 if directive, i, err := getCommentDirective(lines); err != nil {
554 return "", false, err
555 } else if directive != "" {
556 switch directive {
557 case "ignore":
558 return "", true, nil
559 case "start":
560 return getCommentTranslationBlock(lines[i+1:])
561 case "end":
562 return "", false, fmt.Errorf("Unexpected Android.mk:end translation directive")
563 default:
564 return "", false, fmt.Errorf("Unknown Android.mk module translation directive %q", directive)
565 }
566 }
567
568 return "", false, nil
569}
570
571func getCommentTranslationBlock(lines []string) (string, bool, error) {
572 var buf []byte
573
574 for _, line := range lines {
575 if directive := getLineCommentDirective(line); directive != "" {
576 switch directive {
577 case "end":
578 return string(buf), true, nil
579 default:
580 return "", false, fmt.Errorf("Unexpected Android.mk translation directive %q inside start", directive)
581 }
582 } else {
583 buf = append(buf, line...)
584 buf = append(buf, '\n')
585 }
586 }
587
588 return "", false, fmt.Errorf("Missing Android.mk:end translation directive")
589}
590
591func getCommentDirective(lines []string) (directive string, n int, err error) {
592 for i, line := range lines {
593 if directive := getLineCommentDirective(line); directive != "" {
594 return strings.ToLower(directive), i, nil
595 }
596 }
597
598 return "", -1, nil
599}
600
601func getLineCommentDirective(line string) string {
602 line = strings.TrimSpace(line)
603 if strings.HasPrefix(line, "Android.mk:") {
604 line = strings.TrimPrefix(line, "Android.mk:")
605 line = strings.TrimSpace(line)
606 return line
607 }
608
609 return ""
610}
611
Colin Crossb0931242015-06-29 14:18:27 -0700612func (w *androidMkWriter) write(writer io.Writer) (err error) {
613 w.Writer = writer
Andres Moralesda8706f2015-04-29 12:46:49 -0700614
Colin Crossb0931242015-06-29 14:18:27 -0700615 if err = w.handleLocalPath(); err != nil {
Colin Cross26478b72015-06-29 13:46:00 -0700616 return err
617 }
618
619 for _, block := range w.blueprint.Defs {
Andres Moralesda8706f2015-04-29 12:46:49 -0700620 switch block := block.(type) {
621 case *bpparser.Module:
Colin Crossb0931242015-06-29 14:18:27 -0700622 err = w.handleModule(block)
Andres Moralesda8706f2015-04-29 12:46:49 -0700623 case *bpparser.Assignment:
Colin Crossb3245e92015-06-30 16:27:57 -0700624 // Nothing
Colin Crossb0931242015-06-29 14:18:27 -0700625 default:
626 return fmt.Errorf("Unhandled def %v", block)
627 }
628 if err != nil {
629 return err
Andres Moralesda8706f2015-04-29 12:46:49 -0700630 }
631 }
632
Ying Wang38284902015-06-02 18:44:59 -0700633 return nil
Andres Moralesda8706f2015-04-29 12:46:49 -0700634}
635
Colin Crossb3245e92015-06-30 16:27:57 -0700636func translate(rootFile, androidBp, androidMk string) error {
Andres Moralesda8706f2015-04-29 12:46:49 -0700637
Colin Crossb3245e92015-06-30 16:27:57 -0700638 ctx := blueprint.NewContext()
639
640 var blueprintFile *bpparser.File
641
642 _, errs := ctx.WalkBlueprintsFiles(rootFile, func(file *bpparser.File) {
643 if file.Name == androidBp {
644 blueprintFile = file
645 }
646 })
Andres Moralesda8706f2015-04-29 12:46:49 -0700647 if len(errs) > 0 {
Colin Crossb0931242015-06-29 14:18:27 -0700648 return errs[0]
Andres Moralesda8706f2015-04-29 12:46:49 -0700649 }
650
Colin Crossb3245e92015-06-30 16:27:57 -0700651 if blueprintFile == nil {
652 return fmt.Errorf("File %q wasn't parsed from %q", androidBp, rootFile)
653 }
654
Andres Moralesda8706f2015-04-29 12:46:49 -0700655 writer := &androidMkWriter{
Colin Crossb3245e92015-06-30 16:27:57 -0700656 blueprint: blueprintFile,
Ying Wang38284902015-06-02 18:44:59 -0700657 path: path.Dir(androidBp),
Andres Moralesda8706f2015-04-29 12:46:49 -0700658 }
659
Colin Crossb0931242015-06-29 14:18:27 -0700660 buf := &bytes.Buffer{}
661
Colin Crossb3245e92015-06-30 16:27:57 -0700662 err := writer.write(buf)
Ying Wang38284902015-06-02 18:44:59 -0700663 if err != nil {
Colin Crossb0931242015-06-29 14:18:27 -0700664 os.Remove(androidMk)
665 return err
666 }
667
668 f, err := os.Create(androidMk)
669 if err != nil {
670 return err
671 }
672 defer f.Close()
673
674 _, err = f.Write(buf.Bytes())
675
676 return err
677}
678
679func main() {
Colin Crossb3245e92015-06-30 16:27:57 -0700680 if len(os.Args) < 4 {
681 fmt.Fprintln(os.Stderr, "Expected root Android.bp, input and output filename arguments")
Colin Crossb0931242015-06-29 14:18:27 -0700682 os.Exit(1)
683 }
684
Colin Crossb3245e92015-06-30 16:27:57 -0700685 rootFile := os.Args[1]
686 androidBp, err := filepath.Rel(filepath.Dir(rootFile), os.Args[2])
687 if err != nil {
688 fmt.Fprintf(os.Stderr, "Android.bp file %q is not relative to %q: %s\n",
689 os.Args[2], rootFile, err.Error())
690 os.Exit(1)
691 }
692 androidMk := os.Args[3]
Colin Crossb0931242015-06-29 14:18:27 -0700693
Colin Crossb3245e92015-06-30 16:27:57 -0700694 err = translate(rootFile, androidBp, androidMk)
Colin Crossb0931242015-06-29 14:18:27 -0700695 if err != nil {
696 fmt.Fprintf(os.Stderr, "Error translating %s: %s\n", androidBp, err.Error())
Ying Wang38284902015-06-02 18:44:59 -0700697 os.Exit(1)
698 }
Andres Moralesda8706f2015-04-29 12:46:49 -0700699}