blob: 4f9691cbab9fe7b8f23653acba6e0483740d1243 [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 Crossb0931242015-06-29 14:18:27 -070028func (w *androidMkWriter) WriteString(s string) (int, error) {
29 return io.WriteString(w.Writer, s)
30}
31
32func valueToString(value bpparser.Value) (string, error) {
Colin Crossb3245e92015-06-30 16:27:57 -070033 switch value.Type {
34 case bpparser.Bool:
35 return fmt.Sprintf("%t", value.BoolValue), nil
36 case bpparser.String:
37 return fmt.Sprintf("%s", processWildcards(value.StringValue)), nil
38 case bpparser.List:
39 val, err := listToMkString(value.ListValue)
Colin Crossb0931242015-06-29 14:18:27 -070040 if err != nil {
41 return "", err
42 }
Colin Crossb3245e92015-06-30 16:27:57 -070043 return fmt.Sprintf("\\\n%s", val), nil
44 case bpparser.Map:
45 return "", fmt.Errorf("Can't convert map to string")
46 default:
47 return "", fmt.Errorf("ERROR: unsupported type %d", value.Type)
Andres Moralesda8706f2015-04-29 12:46:49 -070048 }
Andres Moralesda8706f2015-04-29 12:46:49 -070049}
50
Dan Willemsen27012122015-06-26 17:40:54 -070051func appendValueToValue(dest bpparser.Value, src bpparser.Value) (bpparser.Value, error) {
52 if src.Type != dest.Type {
53 return bpparser.Value{}, fmt.Errorf("ERROR: source and destination types don't match")
54 }
55 switch dest.Type {
56 case bpparser.List:
57 dest.ListValue = append(dest.ListValue, src.ListValue...)
58 return dest, nil
59 case bpparser.String:
60 dest.StringValue += src.StringValue
61 return dest, nil
62 default:
63 return bpparser.Value{}, fmt.Errorf("ERROR: unsupported append with type %s", dest.Type.String())
64 }
65}
66
Andres Morales8ae47de2015-05-11 12:26:07 -070067func getTopOfAndroidTree(wd string) (string, error) {
68 if !filepath.IsAbs(wd) {
69 return "", errors.New("path must be absolute: " + wd)
70 }
71
72 topfile := "build/soong/bootstrap.bash"
73
74 for "/" != wd {
75 expected := filepath.Join(wd, topfile)
76
77 if _, err := os.Stat(expected); err == nil {
78 // Found the top
79 return wd, nil
80 }
81
82 wd = filepath.Join(wd, "..")
83 }
84
85 return "", errors.New("couldn't find top of tree from " + wd)
86}
87
Andres Moralesaf11df12015-04-30 12:14:34 -070088// TODO: handle non-recursive wildcards?
89func processWildcards(s string) string {
Andres Morales8ae47de2015-05-11 12:26:07 -070090 submatches := recursiveSubdirRegex.FindStringSubmatch(s)
91 if len(submatches) > 2 {
Andres Moralesaf11df12015-04-30 12:14:34 -070092 // Found a wildcard rule
93 return fmt.Sprintf("$(call find-files-in-subdirs, $(LOCAL_PATH), %s, %s)",
Andres Morales8ae47de2015-05-11 12:26:07 -070094 submatches[2], submatches[1])
Andres Moralesaf11df12015-04-30 12:14:34 -070095 }
96
97 return s
98}
99
Colin Crossb0931242015-06-29 14:18:27 -0700100func listToMkString(list []bpparser.Value) (string, error) {
Andres Moralesda8706f2015-04-29 12:46:49 -0700101 lines := make([]string, 0, len(list))
102 for _, tok := range list {
Colin Crossb0931242015-06-29 14:18:27 -0700103 val, err := valueToString(tok)
104 if err != nil {
105 return "", err
106 }
107 lines = append(lines, fmt.Sprintf(" %s", val))
Andres Moralesda8706f2015-04-29 12:46:49 -0700108 }
109
Colin Crossb0931242015-06-29 14:18:27 -0700110 return strings.Join(lines, " \\\n"), nil
Andres Moralesda8706f2015-04-29 12:46:49 -0700111}
112
Andres Moralesaf11df12015-04-30 12:14:34 -0700113func translateTargetConditionals(props []*bpparser.Property,
Colin Crossb0931242015-06-29 14:18:27 -0700114 disabledBuilds map[string]bool, isHostRule bool) (computedProps []string, err error) {
Andres Moralesaf11df12015-04-30 12:14:34 -0700115 for _, target := range props {
116 conditionals := targetScopedPropertyConditionals
Dan Willemsen68fdfcc2015-06-11 14:05:01 -0700117 altConditionals := hostScopedPropertyConditionals
Andres Moralesaf11df12015-04-30 12:14:34 -0700118 if isHostRule {
Dan Willemsen68fdfcc2015-06-11 14:05:01 -0700119 conditionals, altConditionals = altConditionals, conditionals
Andres Moralesaf11df12015-04-30 12:14:34 -0700120 }
121
122 conditional, ok := conditionals[target.Name.Name]
123 if !ok {
Dan Willemsen68fdfcc2015-06-11 14:05:01 -0700124 if _, ok := altConditionals[target.Name.Name]; ok {
125 // This is only for the other build type
126 continue
127 } else {
Colin Crossb0931242015-06-29 14:18:27 -0700128 return nil, fmt.Errorf("Unsupported conditional %q", target.Name.Name)
Dan Willemsen68fdfcc2015-06-11 14:05:01 -0700129 }
Andres Moralesaf11df12015-04-30 12:14:34 -0700130 }
131
132 var scopedProps []string
133 for _, targetScopedProp := range target.Value.MapValue {
134 if mkProp, ok := standardProperties[targetScopedProp.Name.Name]; ok {
Colin Crossb0931242015-06-29 14:18:27 -0700135 val, err := valueToString(targetScopedProp.Value)
136 if err != nil {
137 return nil, err
138 }
Andres Moralesaf11df12015-04-30 12:14:34 -0700139 scopedProps = append(scopedProps, fmt.Sprintf("%s += %s",
Colin Crossb0931242015-06-29 14:18:27 -0700140 mkProp.string, val))
Dan Willemsen57ad08c2015-06-10 16:20:14 -0700141 } else if rwProp, ok := rewriteProperties[targetScopedProp.Name.Name]; ok {
Colin Crossb0931242015-06-29 14:18:27 -0700142 props, err := rwProp.f(rwProp.string, targetScopedProp, nil)
143 if err != nil {
144 return nil, err
145 }
146 scopedProps = append(scopedProps, props...)
Andres Moralesaf11df12015-04-30 12:14:34 -0700147 } else if "disabled" == targetScopedProp.Name.Name {
148 if targetScopedProp.Value.BoolValue {
149 disabledBuilds[target.Name.Name] = true
150 } else {
151 delete(disabledBuilds, target.Name.Name)
152 }
Colin Crossb0931242015-06-29 14:18:27 -0700153 } else {
154 return nil, fmt.Errorf("Unsupported target property %q", targetScopedProp.Name.Name)
Andres Moralesaf11df12015-04-30 12:14:34 -0700155 }
156 }
157
158 if len(scopedProps) > 0 {
Dan Willemsen68fdfcc2015-06-11 14:05:01 -0700159 if conditional != "" {
160 computedProps = append(computedProps, conditional)
161 computedProps = append(computedProps, scopedProps...)
162 computedProps = append(computedProps, "endif")
163 } else {
164 computedProps = append(computedProps, scopedProps...)
165 }
Andres Moralesaf11df12015-04-30 12:14:34 -0700166 }
Andres Moralesda8706f2015-04-29 12:46:49 -0700167 }
Andres Moralesaf11df12015-04-30 12:14:34 -0700168
169 return
170}
171
172func translateSuffixProperties(suffixProps []*bpparser.Property,
Colin Crossb0931242015-06-29 14:18:27 -0700173 suffixMap map[string]string) (computedProps []string, err error) {
Andres Moralesaf11df12015-04-30 12:14:34 -0700174 for _, suffixProp := range suffixProps {
175 if suffix, ok := suffixMap[suffixProp.Name.Name]; ok {
176 for _, stdProp := range suffixProp.Value.MapValue {
177 if mkProp, ok := standardProperties[stdProp.Name.Name]; ok {
Colin Crossb0931242015-06-29 14:18:27 -0700178 val, err := valueToString(stdProp.Value)
179 if err != nil {
180 return nil, err
181 }
182 computedProps = append(computedProps, fmt.Sprintf("%s_%s := %s", mkProp.string, suffix, val))
Dan Willemsen57ad08c2015-06-10 16:20:14 -0700183 } else if rwProp, ok := rewriteProperties[stdProp.Name.Name]; ok {
Colin Crossb0931242015-06-29 14:18:27 -0700184 props, err := rwProp.f(rwProp.string, stdProp, &suffix)
185 if err != nil {
186 return nil, err
187 }
188 computedProps = append(computedProps, props...)
Andres Moralesaf11df12015-04-30 12:14:34 -0700189 } else {
Colin Crossb0931242015-06-29 14:18:27 -0700190 return nil, fmt.Errorf("Unsupported property %q", stdProp.Name.Name)
Andres Moralesaf11df12015-04-30 12:14:34 -0700191 }
192 }
Colin Crossb0931242015-06-29 14:18:27 -0700193 } else {
194 return nil, fmt.Errorf("Unsupported suffix property %q", suffixProp.Name.Name)
Andres Moralesaf11df12015-04-30 12:14:34 -0700195 }
196 }
197 return
198}
199
Colin Crossc41f6302015-06-30 12:19:47 -0700200func appendAssign(name string, prop *bpparser.Property, suffix *string) ([]string, error) {
201 if suffix != nil {
202 name += "_" + *suffix
203 }
204 val, err := valueToString(prop.Value)
205 if err != nil {
206 return nil, err
207 }
208 return []string{
209 fmt.Sprintf("%s += %s", name, val),
210 }, nil
211}
212
Colin Crossb0931242015-06-29 14:18:27 -0700213func prependLocalPath(name string, prop *bpparser.Property, suffix *string) ([]string, error) {
Dan Willemsen57ad08c2015-06-10 16:20:14 -0700214 if suffix != nil {
215 name += "_" + *suffix
216 }
Colin Crossb0931242015-06-29 14:18:27 -0700217 val, err := valueToString(prop.Value)
218 if err != nil {
219 return nil, err
220 }
Colin Crossff3b7952015-06-22 15:39:35 -0700221 return []string{
Colin Crossc41f6302015-06-30 12:19:47 -0700222 fmt.Sprintf("%s += $(addprefix $(LOCAL_PATH)/,%s)", name, val),
Colin Crossb0931242015-06-29 14:18:27 -0700223 }, nil
Dan Willemsen57ad08c2015-06-10 16:20:14 -0700224}
225
Colin Crossb0931242015-06-29 14:18:27 -0700226func prependLocalModule(name string, prop *bpparser.Property, suffix *string) ([]string, error) {
Dan Willemsen1d9f2792015-06-22 15:40:14 -0700227 if suffix != nil {
228 name += "_" + *suffix
229 }
Colin Crossb0931242015-06-29 14:18:27 -0700230 val, err := valueToString(prop.Value)
231 if err != nil {
232 return nil, err
Dan Willemsen1d9f2792015-06-22 15:40:14 -0700233 }
Colin Crossb0931242015-06-29 14:18:27 -0700234 return []string{
235 fmt.Sprintf("%s := $(LOCAL_MODULE)%s\n", name, val),
236 }, nil
Dan Willemsen1d9f2792015-06-22 15:40:14 -0700237}
238
Andres Moralesaf11df12015-04-30 12:14:34 -0700239func (w *androidMkWriter) writeModule(moduleRule string, props []string,
240 disabledBuilds map[string]bool, isHostRule bool) {
241 disabledConditionals := disabledTargetConditionals
242 if isHostRule {
243 disabledConditionals = disabledHostConditionals
244 }
245 for build, _ := range disabledBuilds {
246 if conditional, ok := disabledConditionals[build]; ok {
247 fmt.Fprintf(w, "%s\n", conditional)
248 defer fmt.Fprintf(w, "endif\n")
Andres Moralesda8706f2015-04-29 12:46:49 -0700249 }
Andres Moralesaf11df12015-04-30 12:14:34 -0700250 }
Andres Moralesda8706f2015-04-29 12:46:49 -0700251
Andres Moralesaf11df12015-04-30 12:14:34 -0700252 fmt.Fprintf(w, "include $(CLEAR_VARS)\n")
253 fmt.Fprintf(w, "%s\n", strings.Join(props, "\n"))
254 fmt.Fprintf(w, "include $(%s)\n\n", moduleRule)
255}
Andres Moralesda8706f2015-04-29 12:46:49 -0700256
Colin Crossb0931242015-06-29 14:18:27 -0700257func (w *androidMkWriter) parsePropsAndWriteModule(module *Module) error {
Dan Willemsen3a4045d2015-06-24 15:37:17 -0700258 standardProps := make([]string, 0, len(module.bpmod.Properties))
Andres Moralesaf11df12015-04-30 12:14:34 -0700259 disabledBuilds := make(map[string]bool)
Dan Willemsen3a4045d2015-06-24 15:37:17 -0700260 for _, prop := range module.bpmod.Properties {
Andres Moralesaf11df12015-04-30 12:14:34 -0700261 if mkProp, ok := standardProperties[prop.Name.Name]; ok {
Colin Crossb0931242015-06-29 14:18:27 -0700262 val, err := valueToString(prop.Value)
263 if err != nil {
264 return err
265 }
266 standardProps = append(standardProps, fmt.Sprintf("%s := %s", mkProp.string, val))
Dan Willemsen57ad08c2015-06-10 16:20:14 -0700267 } else if rwProp, ok := rewriteProperties[prop.Name.Name]; ok {
Colin Crossb0931242015-06-29 14:18:27 -0700268 props, err := rwProp.f(rwProp.string, prop, nil)
269 if err != nil {
270 return err
271 }
272 standardProps = append(standardProps, props...)
Andres Moralesaf11df12015-04-30 12:14:34 -0700273 } else if suffixMap, ok := suffixProperties[prop.Name.Name]; ok {
Colin Crossb3245e92015-06-30 16:27:57 -0700274 props, err := translateSuffixProperties(prop.Value.MapValue, suffixMap)
Colin Crossb0931242015-06-29 14:18:27 -0700275 if err != nil {
276 return err
277 }
278 standardProps = append(standardProps, props...)
Andres Moralesaf11df12015-04-30 12:14:34 -0700279 } else if "target" == prop.Name.Name {
Colin Crossb3245e92015-06-30 16:27:57 -0700280 props, err := translateTargetConditionals(prop.Value.MapValue, disabledBuilds, module.isHostRule)
Colin Crossb0931242015-06-29 14:18:27 -0700281 if err != nil {
282 return err
283 }
284 standardProps = append(standardProps, props...)
Dan Willemsen0a544692015-06-24 15:50:07 -0700285 } else if _, ok := ignoredProperties[prop.Name.Name]; ok {
Andres Moralesaf11df12015-04-30 12:14:34 -0700286 } else {
Colin Crossb0931242015-06-29 14:18:27 -0700287 return fmt.Errorf("Unsupported property %q", prop.Name.Name)
Andres Moralesaf11df12015-04-30 12:14:34 -0700288 }
289 }
290
Dan Willemsen3a4045d2015-06-24 15:37:17 -0700291 w.writeModule(module.mkname, standardProps, disabledBuilds, module.isHostRule)
Colin Crossb0931242015-06-29 14:18:27 -0700292
293 return nil
Dan Willemsen68fdfcc2015-06-11 14:05:01 -0700294}
295
Dan Willemsen26173162015-07-06 13:36:50 -0700296func canUseWholeStaticLibrary(m *Module) (bool, error) {
297 ret := true
298
299 isCompatible := func(props Properties, prop *bpparser.Property) error {
300 for _, p := range prop.Value.MapValue {
301 if p.Name.Name == "cflags" {
302 ret = false
303 return nil
304 }
305 if prop.Name.Name == "static" {
306 if p.Name.Name == "srcs" {
307 ret = false
308 return nil
309 }
310 }
311 }
312 return nil
313 }
314
315 err := m.IterateArchPropertiesWithName("shared", isCompatible)
316 if err != nil {
317 return false, err
318 }
319 err = m.IterateArchPropertiesWithName("static", isCompatible)
320 if err != nil {
321 return false, err
322 }
323
324 return ret, nil
325}
326
Colin Crossb0931242015-06-29 14:18:27 -0700327func (w *androidMkWriter) mutateModule(module *Module) (modules []*Module, err error) {
Dan Willemsen3a4045d2015-06-24 15:37:17 -0700328 modules = []*Module{module}
Dan Willemsen49f50452015-06-24 14:56:00 -0700329
Dan Willemsen3a4045d2015-06-24 15:37:17 -0700330 if module.bpname == "cc_library" {
331 modules = []*Module{
332 newModule(module.bpmod),
333 newModule(module.bpmod),
334 }
Dan Willemsen27012122015-06-26 17:40:54 -0700335
336 ccLinkageCopy := func(props Properties, prop *bpparser.Property) error {
337 for _, p := range prop.Value.MapValue {
338 err := props.AppendToProp(p.Name.Name, p)
339 if err != nil {
340 return err
341 }
342 }
343 props.DeleteProp(prop.Name.Name)
344 return nil
345 }
Dan Willemsen26173162015-07-06 13:36:50 -0700346 deleteProp := func(props Properties, prop *bpparser.Property) error {
Dan Willemsen27012122015-06-26 17:40:54 -0700347 props.DeleteProp(prop.Name.Name)
348 return nil
349 }
350
Dan Willemsen26173162015-07-06 13:36:50 -0700351 if ok, err := canUseWholeStaticLibrary(module); err != nil {
352 return nil, err
353 } else if ok {
354 err = modules[0].IterateArchPropertiesWithName("srcs", deleteProp)
355 if err != nil {
356 return nil, err
357 }
358
359 if nameProp, ok := modules[0].Properties().Prop("name"); !ok {
360 return nil, fmt.Errorf("Can't find name property")
361 } else {
362 modules[0].Properties().AppendToProp("whole_static_libs", &bpparser.Property{
363 Value: bpparser.Value{
364 Type: bpparser.List,
365 ListValue: []bpparser.Value{
366 nameProp.Value.Copy(),
367 },
368 },
369 })
370 }
371 }
372
Dan Willemsen3a4045d2015-06-24 15:37:17 -0700373 modules[0].bpname = "cc_library_shared"
Dan Willemsen27012122015-06-26 17:40:54 -0700374 err := modules[0].IterateArchPropertiesWithName("shared", ccLinkageCopy)
375 if err != nil {
376 return nil, err
377 }
Dan Willemsen26173162015-07-06 13:36:50 -0700378 err = modules[0].IterateArchPropertiesWithName("static", deleteProp)
Dan Willemsen27012122015-06-26 17:40:54 -0700379 if err != nil {
380 return nil, err
381 }
382
Dan Willemsen3a4045d2015-06-24 15:37:17 -0700383 modules[1].bpname = "cc_library_static"
Dan Willemsen26173162015-07-06 13:36:50 -0700384 err = modules[1].IterateArchPropertiesWithName("shared", deleteProp)
Dan Willemsen27012122015-06-26 17:40:54 -0700385 if err != nil {
386 return nil, err
387 }
388 err = modules[1].IterateArchPropertiesWithName("static", ccLinkageCopy)
389 if err != nil {
390 return nil, err
391 }
Dan Willemsen3a4045d2015-06-24 15:37:17 -0700392 }
393
394 for _, mod := range modules {
Colin Crossb0931242015-06-29 14:18:27 -0700395 err := mod.translateRuleName()
396 if err != nil {
397 return nil, err
398 }
Dan Willemsen27012122015-06-26 17:40:54 -0700399 if mod.isHostRule || !mod.PropBool("host_supported") {
Dan Willemsen3a4045d2015-06-24 15:37:17 -0700400 continue
401 }
402
403 m := &Module{
404 bpmod: mod.bpmod,
405 bpname: mod.bpname,
406 isHostRule: true,
407 }
Colin Crossb0931242015-06-29 14:18:27 -0700408 err = m.translateRuleName()
409 if err != nil {
410 return nil, err
411 }
Dan Willemsen3a4045d2015-06-24 15:37:17 -0700412 modules = append(modules, m)
Dan Willemsen68fdfcc2015-06-11 14:05:01 -0700413 }
414
Dan Willemsen49f50452015-06-24 14:56:00 -0700415 return
416}
Dan Willemsen68fdfcc2015-06-11 14:05:01 -0700417
Colin Crossb0931242015-06-29 14:18:27 -0700418func (w *androidMkWriter) handleModule(inputModule *bpparser.Module) error {
Colin Crossb1a66c02015-06-29 16:24:57 -0700419 comment := w.getCommentBlock(inputModule.Type.Pos)
420 if translation, translated, err := getCommentTranslation(comment); err != nil {
421 return err
422 } else if translated {
423 w.WriteString(translation)
424 return nil
425 }
426
Colin Cross70a5f072015-06-29 17:44:56 -0700427 if ignoredModuleType[inputModule.Type.Name] {
428 return nil
429 }
430
Colin Crossb0931242015-06-29 14:18:27 -0700431 modules, err := w.mutateModule(newModule(inputModule))
432 if err != nil {
433 return err
434 }
Dan Willemsen49f50452015-06-24 14:56:00 -0700435
436 for _, module := range modules {
Colin Crossb0931242015-06-29 14:18:27 -0700437 err := w.parsePropsAndWriteModule(module)
438 if err != nil {
439 return err
440 }
Andres Moralesaf11df12015-04-30 12:14:34 -0700441 }
Colin Crossb0931242015-06-29 14:18:27 -0700442
443 return nil
Andres Moralesaf11df12015-04-30 12:14:34 -0700444}
445
446func (w *androidMkWriter) handleSubdirs(value bpparser.Value) {
Andres Morales8ae47de2015-05-11 12:26:07 -0700447 subdirs := make([]string, 0, len(value.ListValue))
448 for _, tok := range value.ListValue {
449 subdirs = append(subdirs, tok.StringValue)
Andres Moralesda8706f2015-04-29 12:46:49 -0700450 }
Ying Wang38284902015-06-02 18:44:59 -0700451 // The current makefile may be generated to outside the source tree (such as the out directory), with a different structure.
452 fmt.Fprintf(w, "# Uncomment the following line if you really want to include subdir Android.mks.\n")
453 fmt.Fprintf(w, "# include $(wildcard $(addsuffix $(LOCAL_PATH)/%s/, Android.mk))\n", strings.Join(subdirs, " "))
Andres Moralesda8706f2015-04-29 12:46:49 -0700454}
455
Andres Morales8ae47de2015-05-11 12:26:07 -0700456func (w *androidMkWriter) handleLocalPath() error {
Colin Crossb3245e92015-06-30 16:27:57 -0700457 w.WriteString("LOCAL_PATH := " + w.path + "\n")
Dan Willemsenc2666e62015-06-10 16:18:58 -0700458 w.WriteString("LOCAL_MODULE_MAKEFILE := $(lastword $(MAKEFILE_LIST))\n\n")
Andres Morales8ae47de2015-05-11 12:26:07 -0700459 return nil
460}
461
Colin Crossb1a66c02015-06-29 16:24:57 -0700462// Returns any block comment on the line preceding pos as a string
463func (w *androidMkWriter) getCommentBlock(pos scanner.Position) string {
464 var buf []byte
465
466 comments := w.blueprint.Comments
467 for i, c := range comments {
468 if c.EndLine() == pos.Line-1 {
469 line := pos.Line
470 for j := i; j >= 0; j-- {
471 c = comments[j]
472 if c.EndLine() == line-1 {
473 buf = append([]byte(c.Text()), buf...)
474 line = c.Pos.Line
475 } else {
476 break
477 }
478 }
479 }
480 }
481
482 return string(buf)
483}
484
485func getCommentTranslation(comment string) (string, bool, error) {
486 lines := strings.Split(comment, "\n")
487
488 if directive, i, err := getCommentDirective(lines); err != nil {
489 return "", false, err
490 } else if directive != "" {
491 switch directive {
492 case "ignore":
493 return "", true, nil
494 case "start":
495 return getCommentTranslationBlock(lines[i+1:])
496 case "end":
497 return "", false, fmt.Errorf("Unexpected Android.mk:end translation directive")
498 default:
499 return "", false, fmt.Errorf("Unknown Android.mk module translation directive %q", directive)
500 }
501 }
502
503 return "", false, nil
504}
505
506func getCommentTranslationBlock(lines []string) (string, bool, error) {
507 var buf []byte
508
509 for _, line := range lines {
510 if directive := getLineCommentDirective(line); directive != "" {
511 switch directive {
512 case "end":
513 return string(buf), true, nil
514 default:
515 return "", false, fmt.Errorf("Unexpected Android.mk translation directive %q inside start", directive)
516 }
517 } else {
518 buf = append(buf, line...)
519 buf = append(buf, '\n')
520 }
521 }
522
523 return "", false, fmt.Errorf("Missing Android.mk:end translation directive")
524}
525
526func getCommentDirective(lines []string) (directive string, n int, err error) {
527 for i, line := range lines {
528 if directive := getLineCommentDirective(line); directive != "" {
529 return strings.ToLower(directive), i, nil
530 }
531 }
532
533 return "", -1, nil
534}
535
536func getLineCommentDirective(line string) string {
537 line = strings.TrimSpace(line)
538 if strings.HasPrefix(line, "Android.mk:") {
539 line = strings.TrimPrefix(line, "Android.mk:")
540 line = strings.TrimSpace(line)
541 return line
542 }
543
544 return ""
545}
546
Colin Crossb0931242015-06-29 14:18:27 -0700547func (w *androidMkWriter) write(writer io.Writer) (err error) {
548 w.Writer = writer
Andres Moralesda8706f2015-04-29 12:46:49 -0700549
Colin Crossb0931242015-06-29 14:18:27 -0700550 if err = w.handleLocalPath(); err != nil {
Colin Cross26478b72015-06-29 13:46:00 -0700551 return err
552 }
553
554 for _, block := range w.blueprint.Defs {
Andres Moralesda8706f2015-04-29 12:46:49 -0700555 switch block := block.(type) {
556 case *bpparser.Module:
Colin Crossb0931242015-06-29 14:18:27 -0700557 err = w.handleModule(block)
Andres Moralesda8706f2015-04-29 12:46:49 -0700558 case *bpparser.Assignment:
Colin Crossb3245e92015-06-30 16:27:57 -0700559 // Nothing
Colin Crossb0931242015-06-29 14:18:27 -0700560 default:
561 return fmt.Errorf("Unhandled def %v", block)
562 }
563 if err != nil {
564 return err
Andres Moralesda8706f2015-04-29 12:46:49 -0700565 }
566 }
567
Ying Wang38284902015-06-02 18:44:59 -0700568 return nil
Andres Moralesda8706f2015-04-29 12:46:49 -0700569}
570
Colin Crossb3245e92015-06-30 16:27:57 -0700571func translate(rootFile, androidBp, androidMk string) error {
Andres Moralesda8706f2015-04-29 12:46:49 -0700572
Colin Crossb3245e92015-06-30 16:27:57 -0700573 ctx := blueprint.NewContext()
574
575 var blueprintFile *bpparser.File
576
577 _, errs := ctx.WalkBlueprintsFiles(rootFile, func(file *bpparser.File) {
578 if file.Name == androidBp {
579 blueprintFile = file
580 }
581 })
Andres Moralesda8706f2015-04-29 12:46:49 -0700582 if len(errs) > 0 {
Colin Crossb0931242015-06-29 14:18:27 -0700583 return errs[0]
Andres Moralesda8706f2015-04-29 12:46:49 -0700584 }
585
Colin Crossb3245e92015-06-30 16:27:57 -0700586 if blueprintFile == nil {
587 return fmt.Errorf("File %q wasn't parsed from %q", androidBp, rootFile)
588 }
589
Andres Moralesda8706f2015-04-29 12:46:49 -0700590 writer := &androidMkWriter{
Colin Crossb3245e92015-06-30 16:27:57 -0700591 blueprint: blueprintFile,
Ying Wang38284902015-06-02 18:44:59 -0700592 path: path.Dir(androidBp),
Andres Moralesda8706f2015-04-29 12:46:49 -0700593 }
594
Colin Crossb0931242015-06-29 14:18:27 -0700595 buf := &bytes.Buffer{}
596
Colin Crossb3245e92015-06-30 16:27:57 -0700597 err := writer.write(buf)
Ying Wang38284902015-06-02 18:44:59 -0700598 if err != nil {
Colin Crossb0931242015-06-29 14:18:27 -0700599 os.Remove(androidMk)
600 return err
601 }
602
603 f, err := os.Create(androidMk)
604 if err != nil {
605 return err
606 }
607 defer f.Close()
608
609 _, err = f.Write(buf.Bytes())
610
611 return err
612}
613
614func main() {
Colin Crossb3245e92015-06-30 16:27:57 -0700615 if len(os.Args) < 4 {
616 fmt.Fprintln(os.Stderr, "Expected root Android.bp, input and output filename arguments")
Colin Crossb0931242015-06-29 14:18:27 -0700617 os.Exit(1)
618 }
619
Colin Crossb3245e92015-06-30 16:27:57 -0700620 rootFile := os.Args[1]
621 androidBp, err := filepath.Rel(filepath.Dir(rootFile), os.Args[2])
622 if err != nil {
623 fmt.Fprintf(os.Stderr, "Android.bp file %q is not relative to %q: %s\n",
624 os.Args[2], rootFile, err.Error())
625 os.Exit(1)
626 }
627 androidMk := os.Args[3]
Colin Crossb0931242015-06-29 14:18:27 -0700628
Colin Crossb3245e92015-06-30 16:27:57 -0700629 err = translate(rootFile, androidBp, androidMk)
Colin Crossb0931242015-06-29 14:18:27 -0700630 if err != nil {
631 fmt.Fprintf(os.Stderr, "Error translating %s: %s\n", androidBp, err.Error())
Ying Wang38284902015-06-02 18:44:59 -0700632 os.Exit(1)
633 }
Andres Moralesda8706f2015-04-29 12:46:49 -0700634}