blob: bf24c1ba41b5eda629c2bdb892c0898e82cf9052 [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
Colin Crossaee540a2015-07-06 17:48:31 -0700239func versionScript(name string, prop *bpparser.Property, suffix *string) ([]string, error) {
240 if suffix != nil {
241 name += "_" + *suffix
242 }
243 val, err := valueToString(prop.Value)
244 if err != nil {
245 return nil, err
246 }
247 return []string{
248 fmt.Sprintf("%s += -Wl,--version-script,$(LOCAL_PATH)/%s\n", name, val),
249 }, nil
250}
251
Andres Moralesaf11df12015-04-30 12:14:34 -0700252func (w *androidMkWriter) writeModule(moduleRule string, props []string,
253 disabledBuilds map[string]bool, isHostRule bool) {
254 disabledConditionals := disabledTargetConditionals
255 if isHostRule {
256 disabledConditionals = disabledHostConditionals
257 }
258 for build, _ := range disabledBuilds {
259 if conditional, ok := disabledConditionals[build]; ok {
260 fmt.Fprintf(w, "%s\n", conditional)
261 defer fmt.Fprintf(w, "endif\n")
Andres Moralesda8706f2015-04-29 12:46:49 -0700262 }
Andres Moralesaf11df12015-04-30 12:14:34 -0700263 }
Andres Moralesda8706f2015-04-29 12:46:49 -0700264
Andres Moralesaf11df12015-04-30 12:14:34 -0700265 fmt.Fprintf(w, "include $(CLEAR_VARS)\n")
266 fmt.Fprintf(w, "%s\n", strings.Join(props, "\n"))
267 fmt.Fprintf(w, "include $(%s)\n\n", moduleRule)
268}
Andres Moralesda8706f2015-04-29 12:46:49 -0700269
Colin Crossb0931242015-06-29 14:18:27 -0700270func (w *androidMkWriter) parsePropsAndWriteModule(module *Module) error {
Dan Willemsen3a4045d2015-06-24 15:37:17 -0700271 standardProps := make([]string, 0, len(module.bpmod.Properties))
Andres Moralesaf11df12015-04-30 12:14:34 -0700272 disabledBuilds := make(map[string]bool)
Dan Willemsen3a4045d2015-06-24 15:37:17 -0700273 for _, prop := range module.bpmod.Properties {
Andres Moralesaf11df12015-04-30 12:14:34 -0700274 if mkProp, ok := standardProperties[prop.Name.Name]; ok {
Colin Crossb0931242015-06-29 14:18:27 -0700275 val, err := valueToString(prop.Value)
276 if err != nil {
277 return err
278 }
279 standardProps = append(standardProps, fmt.Sprintf("%s := %s", mkProp.string, val))
Dan Willemsen57ad08c2015-06-10 16:20:14 -0700280 } else if rwProp, ok := rewriteProperties[prop.Name.Name]; ok {
Colin Crossb0931242015-06-29 14:18:27 -0700281 props, err := rwProp.f(rwProp.string, prop, nil)
282 if err != nil {
283 return err
284 }
285 standardProps = append(standardProps, props...)
Andres Moralesaf11df12015-04-30 12:14:34 -0700286 } else if suffixMap, ok := suffixProperties[prop.Name.Name]; ok {
Colin Crossb3245e92015-06-30 16:27:57 -0700287 props, err := translateSuffixProperties(prop.Value.MapValue, suffixMap)
Colin Crossb0931242015-06-29 14:18:27 -0700288 if err != nil {
289 return err
290 }
291 standardProps = append(standardProps, props...)
Andres Moralesaf11df12015-04-30 12:14:34 -0700292 } else if "target" == prop.Name.Name {
Colin Crossb3245e92015-06-30 16:27:57 -0700293 props, err := translateTargetConditionals(prop.Value.MapValue, disabledBuilds, module.isHostRule)
Colin Crossb0931242015-06-29 14:18:27 -0700294 if err != nil {
295 return err
296 }
297 standardProps = append(standardProps, props...)
Dan Willemsen0a544692015-06-24 15:50:07 -0700298 } else if _, ok := ignoredProperties[prop.Name.Name]; ok {
Andres Moralesaf11df12015-04-30 12:14:34 -0700299 } else {
Colin Crossb0931242015-06-29 14:18:27 -0700300 return fmt.Errorf("Unsupported property %q", prop.Name.Name)
Andres Moralesaf11df12015-04-30 12:14:34 -0700301 }
302 }
303
Dan Willemsen3a4045d2015-06-24 15:37:17 -0700304 w.writeModule(module.mkname, standardProps, disabledBuilds, module.isHostRule)
Colin Crossb0931242015-06-29 14:18:27 -0700305
306 return nil
Dan Willemsen68fdfcc2015-06-11 14:05:01 -0700307}
308
Dan Willemsen26173162015-07-06 13:36:50 -0700309func canUseWholeStaticLibrary(m *Module) (bool, error) {
310 ret := true
311
312 isCompatible := func(props Properties, prop *bpparser.Property) error {
313 for _, p := range prop.Value.MapValue {
314 if p.Name.Name == "cflags" {
315 ret = false
316 return nil
317 }
318 if prop.Name.Name == "static" {
319 if p.Name.Name == "srcs" {
320 ret = false
321 return nil
322 }
323 }
324 }
325 return nil
326 }
327
328 err := m.IterateArchPropertiesWithName("shared", isCompatible)
329 if err != nil {
330 return false, err
331 }
332 err = m.IterateArchPropertiesWithName("static", isCompatible)
333 if err != nil {
334 return false, err
335 }
336
337 return ret, nil
338}
339
Colin Crossb0931242015-06-29 14:18:27 -0700340func (w *androidMkWriter) mutateModule(module *Module) (modules []*Module, err error) {
Dan Willemsen3a4045d2015-06-24 15:37:17 -0700341 modules = []*Module{module}
Dan Willemsen49f50452015-06-24 14:56:00 -0700342
Dan Willemsen3a4045d2015-06-24 15:37:17 -0700343 if module.bpname == "cc_library" {
344 modules = []*Module{
345 newModule(module.bpmod),
346 newModule(module.bpmod),
347 }
Dan Willemsen27012122015-06-26 17:40:54 -0700348
349 ccLinkageCopy := func(props Properties, prop *bpparser.Property) error {
350 for _, p := range prop.Value.MapValue {
351 err := props.AppendToProp(p.Name.Name, p)
352 if err != nil {
353 return err
354 }
355 }
356 props.DeleteProp(prop.Name.Name)
357 return nil
358 }
Dan Willemsen26173162015-07-06 13:36:50 -0700359 deleteProp := func(props Properties, prop *bpparser.Property) error {
Dan Willemsen27012122015-06-26 17:40:54 -0700360 props.DeleteProp(prop.Name.Name)
361 return nil
362 }
363
Dan Willemsen26173162015-07-06 13:36:50 -0700364 if ok, err := canUseWholeStaticLibrary(module); err != nil {
365 return nil, err
366 } else if ok {
367 err = modules[0].IterateArchPropertiesWithName("srcs", deleteProp)
368 if err != nil {
369 return nil, err
370 }
371
372 if nameProp, ok := modules[0].Properties().Prop("name"); !ok {
373 return nil, fmt.Errorf("Can't find name property")
374 } else {
375 modules[0].Properties().AppendToProp("whole_static_libs", &bpparser.Property{
376 Value: bpparser.Value{
377 Type: bpparser.List,
378 ListValue: []bpparser.Value{
379 nameProp.Value.Copy(),
380 },
381 },
382 })
383 }
384 }
385
Dan Willemsen3a4045d2015-06-24 15:37:17 -0700386 modules[0].bpname = "cc_library_shared"
Dan Willemsen27012122015-06-26 17:40:54 -0700387 err := modules[0].IterateArchPropertiesWithName("shared", ccLinkageCopy)
388 if err != nil {
389 return nil, err
390 }
Dan Willemsen26173162015-07-06 13:36:50 -0700391 err = modules[0].IterateArchPropertiesWithName("static", deleteProp)
Dan Willemsen27012122015-06-26 17:40:54 -0700392 if err != nil {
393 return nil, err
394 }
395
Dan Willemsen3a4045d2015-06-24 15:37:17 -0700396 modules[1].bpname = "cc_library_static"
Dan Willemsen26173162015-07-06 13:36:50 -0700397 err = modules[1].IterateArchPropertiesWithName("shared", deleteProp)
Dan Willemsen27012122015-06-26 17:40:54 -0700398 if err != nil {
399 return nil, err
400 }
401 err = modules[1].IterateArchPropertiesWithName("static", ccLinkageCopy)
402 if err != nil {
403 return nil, err
404 }
Dan Willemsen3a4045d2015-06-24 15:37:17 -0700405 }
406
407 for _, mod := range modules {
Colin Crossb0931242015-06-29 14:18:27 -0700408 err := mod.translateRuleName()
409 if err != nil {
410 return nil, err
411 }
Dan Willemsen27012122015-06-26 17:40:54 -0700412 if mod.isHostRule || !mod.PropBool("host_supported") {
Dan Willemsen3a4045d2015-06-24 15:37:17 -0700413 continue
414 }
415
416 m := &Module{
417 bpmod: mod.bpmod,
418 bpname: mod.bpname,
419 isHostRule: true,
420 }
Colin Crossb0931242015-06-29 14:18:27 -0700421 err = m.translateRuleName()
422 if err != nil {
423 return nil, err
424 }
Dan Willemsen3a4045d2015-06-24 15:37:17 -0700425 modules = append(modules, m)
Dan Willemsen68fdfcc2015-06-11 14:05:01 -0700426 }
427
Dan Willemsen49f50452015-06-24 14:56:00 -0700428 return
429}
Dan Willemsen68fdfcc2015-06-11 14:05:01 -0700430
Colin Crossb0931242015-06-29 14:18:27 -0700431func (w *androidMkWriter) handleModule(inputModule *bpparser.Module) error {
Colin Crossb1a66c02015-06-29 16:24:57 -0700432 comment := w.getCommentBlock(inputModule.Type.Pos)
433 if translation, translated, err := getCommentTranslation(comment); err != nil {
434 return err
435 } else if translated {
436 w.WriteString(translation)
437 return nil
438 }
439
Colin Cross70a5f072015-06-29 17:44:56 -0700440 if ignoredModuleType[inputModule.Type.Name] {
441 return nil
442 }
443
Colin Crossb0931242015-06-29 14:18:27 -0700444 modules, err := w.mutateModule(newModule(inputModule))
445 if err != nil {
446 return err
447 }
Dan Willemsen49f50452015-06-24 14:56:00 -0700448
449 for _, module := range modules {
Colin Crossb0931242015-06-29 14:18:27 -0700450 err := w.parsePropsAndWriteModule(module)
451 if err != nil {
452 return err
453 }
Andres Moralesaf11df12015-04-30 12:14:34 -0700454 }
Colin Crossb0931242015-06-29 14:18:27 -0700455
456 return nil
Andres Moralesaf11df12015-04-30 12:14:34 -0700457}
458
459func (w *androidMkWriter) handleSubdirs(value bpparser.Value) {
Andres Morales8ae47de2015-05-11 12:26:07 -0700460 subdirs := make([]string, 0, len(value.ListValue))
461 for _, tok := range value.ListValue {
462 subdirs = append(subdirs, tok.StringValue)
Andres Moralesda8706f2015-04-29 12:46:49 -0700463 }
Ying Wang38284902015-06-02 18:44:59 -0700464 // The current makefile may be generated to outside the source tree (such as the out directory), with a different structure.
465 fmt.Fprintf(w, "# Uncomment the following line if you really want to include subdir Android.mks.\n")
466 fmt.Fprintf(w, "# include $(wildcard $(addsuffix $(LOCAL_PATH)/%s/, Android.mk))\n", strings.Join(subdirs, " "))
Andres Moralesda8706f2015-04-29 12:46:49 -0700467}
468
Andres Morales8ae47de2015-05-11 12:26:07 -0700469func (w *androidMkWriter) handleLocalPath() error {
Colin Crossb3245e92015-06-30 16:27:57 -0700470 w.WriteString("LOCAL_PATH := " + w.path + "\n")
Dan Willemsenc2666e62015-06-10 16:18:58 -0700471 w.WriteString("LOCAL_MODULE_MAKEFILE := $(lastword $(MAKEFILE_LIST))\n\n")
Andres Morales8ae47de2015-05-11 12:26:07 -0700472 return nil
473}
474
Colin Crossb1a66c02015-06-29 16:24:57 -0700475// Returns any block comment on the line preceding pos as a string
476func (w *androidMkWriter) getCommentBlock(pos scanner.Position) string {
477 var buf []byte
478
479 comments := w.blueprint.Comments
480 for i, c := range comments {
481 if c.EndLine() == pos.Line-1 {
482 line := pos.Line
483 for j := i; j >= 0; j-- {
484 c = comments[j]
485 if c.EndLine() == line-1 {
486 buf = append([]byte(c.Text()), buf...)
487 line = c.Pos.Line
488 } else {
489 break
490 }
491 }
492 }
493 }
494
495 return string(buf)
496}
497
498func getCommentTranslation(comment string) (string, bool, error) {
499 lines := strings.Split(comment, "\n")
500
501 if directive, i, err := getCommentDirective(lines); err != nil {
502 return "", false, err
503 } else if directive != "" {
504 switch directive {
505 case "ignore":
506 return "", true, nil
507 case "start":
508 return getCommentTranslationBlock(lines[i+1:])
509 case "end":
510 return "", false, fmt.Errorf("Unexpected Android.mk:end translation directive")
511 default:
512 return "", false, fmt.Errorf("Unknown Android.mk module translation directive %q", directive)
513 }
514 }
515
516 return "", false, nil
517}
518
519func getCommentTranslationBlock(lines []string) (string, bool, error) {
520 var buf []byte
521
522 for _, line := range lines {
523 if directive := getLineCommentDirective(line); directive != "" {
524 switch directive {
525 case "end":
526 return string(buf), true, nil
527 default:
528 return "", false, fmt.Errorf("Unexpected Android.mk translation directive %q inside start", directive)
529 }
530 } else {
531 buf = append(buf, line...)
532 buf = append(buf, '\n')
533 }
534 }
535
536 return "", false, fmt.Errorf("Missing Android.mk:end translation directive")
537}
538
539func getCommentDirective(lines []string) (directive string, n int, err error) {
540 for i, line := range lines {
541 if directive := getLineCommentDirective(line); directive != "" {
542 return strings.ToLower(directive), i, nil
543 }
544 }
545
546 return "", -1, nil
547}
548
549func getLineCommentDirective(line string) string {
550 line = strings.TrimSpace(line)
551 if strings.HasPrefix(line, "Android.mk:") {
552 line = strings.TrimPrefix(line, "Android.mk:")
553 line = strings.TrimSpace(line)
554 return line
555 }
556
557 return ""
558}
559
Colin Crossb0931242015-06-29 14:18:27 -0700560func (w *androidMkWriter) write(writer io.Writer) (err error) {
561 w.Writer = writer
Andres Moralesda8706f2015-04-29 12:46:49 -0700562
Colin Crossb0931242015-06-29 14:18:27 -0700563 if err = w.handleLocalPath(); err != nil {
Colin Cross26478b72015-06-29 13:46:00 -0700564 return err
565 }
566
567 for _, block := range w.blueprint.Defs {
Andres Moralesda8706f2015-04-29 12:46:49 -0700568 switch block := block.(type) {
569 case *bpparser.Module:
Colin Crossb0931242015-06-29 14:18:27 -0700570 err = w.handleModule(block)
Andres Moralesda8706f2015-04-29 12:46:49 -0700571 case *bpparser.Assignment:
Colin Crossb3245e92015-06-30 16:27:57 -0700572 // Nothing
Colin Crossb0931242015-06-29 14:18:27 -0700573 default:
574 return fmt.Errorf("Unhandled def %v", block)
575 }
576 if err != nil {
577 return err
Andres Moralesda8706f2015-04-29 12:46:49 -0700578 }
579 }
580
Ying Wang38284902015-06-02 18:44:59 -0700581 return nil
Andres Moralesda8706f2015-04-29 12:46:49 -0700582}
583
Colin Crossb3245e92015-06-30 16:27:57 -0700584func translate(rootFile, androidBp, androidMk string) error {
Andres Moralesda8706f2015-04-29 12:46:49 -0700585
Colin Crossb3245e92015-06-30 16:27:57 -0700586 ctx := blueprint.NewContext()
587
588 var blueprintFile *bpparser.File
589
590 _, errs := ctx.WalkBlueprintsFiles(rootFile, func(file *bpparser.File) {
591 if file.Name == androidBp {
592 blueprintFile = file
593 }
594 })
Andres Moralesda8706f2015-04-29 12:46:49 -0700595 if len(errs) > 0 {
Colin Crossb0931242015-06-29 14:18:27 -0700596 return errs[0]
Andres Moralesda8706f2015-04-29 12:46:49 -0700597 }
598
Colin Crossb3245e92015-06-30 16:27:57 -0700599 if blueprintFile == nil {
600 return fmt.Errorf("File %q wasn't parsed from %q", androidBp, rootFile)
601 }
602
Andres Moralesda8706f2015-04-29 12:46:49 -0700603 writer := &androidMkWriter{
Colin Crossb3245e92015-06-30 16:27:57 -0700604 blueprint: blueprintFile,
Ying Wang38284902015-06-02 18:44:59 -0700605 path: path.Dir(androidBp),
Andres Moralesda8706f2015-04-29 12:46:49 -0700606 }
607
Colin Crossb0931242015-06-29 14:18:27 -0700608 buf := &bytes.Buffer{}
609
Colin Crossb3245e92015-06-30 16:27:57 -0700610 err := writer.write(buf)
Ying Wang38284902015-06-02 18:44:59 -0700611 if err != nil {
Colin Crossb0931242015-06-29 14:18:27 -0700612 os.Remove(androidMk)
613 return err
614 }
615
616 f, err := os.Create(androidMk)
617 if err != nil {
618 return err
619 }
620 defer f.Close()
621
622 _, err = f.Write(buf.Bytes())
623
624 return err
625}
626
627func main() {
Colin Crossb3245e92015-06-30 16:27:57 -0700628 if len(os.Args) < 4 {
629 fmt.Fprintln(os.Stderr, "Expected root Android.bp, input and output filename arguments")
Colin Crossb0931242015-06-29 14:18:27 -0700630 os.Exit(1)
631 }
632
Colin Crossb3245e92015-06-30 16:27:57 -0700633 rootFile := os.Args[1]
634 androidBp, err := filepath.Rel(filepath.Dir(rootFile), os.Args[2])
635 if err != nil {
636 fmt.Fprintf(os.Stderr, "Android.bp file %q is not relative to %q: %s\n",
637 os.Args[2], rootFile, err.Error())
638 os.Exit(1)
639 }
640 androidMk := os.Args[3]
Colin Crossb0931242015-06-29 14:18:27 -0700641
Colin Crossb3245e92015-06-30 16:27:57 -0700642 err = translate(rootFile, androidBp, androidMk)
Colin Crossb0931242015-06-29 14:18:27 -0700643 if err != nil {
644 fmt.Fprintf(os.Stderr, "Error translating %s: %s\n", androidBp, err.Error())
Ying Wang38284902015-06-02 18:44:59 -0700645 os.Exit(1)
646 }
Andres Moralesda8706f2015-04-29 12:46:49 -0700647}