blob: b1e364c96124181544b93e74d4ce800f31f6f3ab [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 Crossec193632015-07-06 17:49:43 -0700178var secondTargetReplacer = strings.NewReplacer("TARGET_", "TARGET_2ND_")
179
Andres Moralesaf11df12015-04-30 12:14:34 -0700180func translateSuffixProperties(suffixProps []*bpparser.Property,
Colin Crossb0931242015-06-29 14:18:27 -0700181 suffixMap map[string]string) (computedProps []string, err error) {
Andres Moralesaf11df12015-04-30 12:14:34 -0700182 for _, suffixProp := range suffixProps {
183 if suffix, ok := suffixMap[suffixProp.Name.Name]; ok {
184 for _, stdProp := range suffixProp.Value.MapValue {
Colin Cross3cc00f12015-07-07 12:22:51 -0700185 if assignment, ok, err := translateSingleProperty(stdProp); err != nil {
186 return nil, err
187 } else if ok {
188 computedProps = append(computedProps, assignment.assignmentWithSuffix(suffix))
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 Crossec193632015-07-06 17:49:43 -0700193 } else if variant, ok := cpuVariantConditionals[suffixProp.Name.Name]; ok {
194 var conditionalProps []propAssignment
195 for _, stdProp := range suffixProp.Value.MapValue {
196 if assignment, ok, err := translateSingleProperty(stdProp); err != nil {
197 return nil, err
198 } else if ok {
199 conditionalProps = append(conditionalProps, assignment)
200 } else {
201 return nil, fmt.Errorf("Unsupported property %q", stdProp.Name.Name)
202 }
203 }
204
205 appendComputedProps := func() {
206 computedProps = append(computedProps, variant.conditional)
207 for _, prop := range conditionalProps {
208 prop.assigner = "+="
209 computedProps = append(computedProps, prop.assignmentWithSuffix(variant.suffix))
210 }
211 computedProps = append(computedProps, "endif")
212 }
213
214 appendComputedProps()
215 if variant.secondArch {
216 variant.conditional = secondTargetReplacer.Replace(variant.conditional)
217 variant.suffix = secondTargetReplacer.Replace(variant.suffix)
218 appendComputedProps()
219 }
Colin Crossb0931242015-06-29 14:18:27 -0700220 } else {
221 return nil, fmt.Errorf("Unsupported suffix property %q", suffixProp.Name.Name)
Andres Moralesaf11df12015-04-30 12:14:34 -0700222 }
223 }
224 return
225}
226
Colin Cross3cc00f12015-07-07 12:22:51 -0700227func translateSingleProperty(prop *bpparser.Property) (propAssignment, bool, error) {
228 var assignment propAssignment
229 if mkProp, ok := standardProperties[prop.Name.Name]; ok {
230 name := mkProp.string
231 val, err := valueToString(prop.Value)
232 if err != nil {
233 return propAssignment{}, false, err
234 }
235 assignment = propAssignment{name, ":=", val}
236 } else if rwProp, ok := rewriteProperties[prop.Name.Name]; ok {
237 val, err := valueToString(prop.Value)
238 if err != nil {
239 return propAssignment{}, false, err
240 }
241 assignment, err = rwProp.f(rwProp.string, prop, val)
242 if err != nil {
243 return propAssignment{}, false, err
244 }
245 } else {
246 // Unhandled, return false with no error to tell the caller to handle it
247 return propAssignment{}, false, nil
Colin Crossc41f6302015-06-30 12:19:47 -0700248 }
Colin Cross3cc00f12015-07-07 12:22:51 -0700249 return assignment, true, nil
Colin Crossc41f6302015-06-30 12:19:47 -0700250}
251
Colin Cross3cc00f12015-07-07 12:22:51 -0700252func appendAssign(name string, prop *bpparser.Property, val string) (propAssignment, error) {
253 return propAssignment{name, "+=", val}, nil
Dan Willemsen57ad08c2015-06-10 16:20:14 -0700254}
255
Colin Cross3cc00f12015-07-07 12:22:51 -0700256func prependLocalPath(name string, prop *bpparser.Property, val string) (propAssignment, error) {
257 return propAssignment{name, "+=", fmt.Sprintf("$(addprefix $(LOCAL_PATH)/,%s)", val)}, nil
Dan Willemsen1d9f2792015-06-22 15:40:14 -0700258}
259
Colin Cross3cc00f12015-07-07 12:22:51 -0700260func prependLocalModule(name string, prop *bpparser.Property, val string) (propAssignment, error) {
261 return propAssignment{name, ":=", "$(LOCAL_MODULE)" + val}, nil
262}
263
264func versionScript(name string, prop *bpparser.Property, val string) (propAssignment, error) {
265 return propAssignment{name, "+=", "-Wl,--version-script,$(LOCAL_PATH)/" + val}, nil
Colin Crossaee540a2015-07-06 17:48:31 -0700266}
267
Andres Moralesaf11df12015-04-30 12:14:34 -0700268func (w *androidMkWriter) writeModule(moduleRule string, props []string,
269 disabledBuilds map[string]bool, isHostRule bool) {
270 disabledConditionals := disabledTargetConditionals
271 if isHostRule {
272 disabledConditionals = disabledHostConditionals
273 }
274 for build, _ := range disabledBuilds {
275 if conditional, ok := disabledConditionals[build]; ok {
276 fmt.Fprintf(w, "%s\n", conditional)
277 defer fmt.Fprintf(w, "endif\n")
Andres Moralesda8706f2015-04-29 12:46:49 -0700278 }
Andres Moralesaf11df12015-04-30 12:14:34 -0700279 }
Andres Moralesda8706f2015-04-29 12:46:49 -0700280
Andres Moralesaf11df12015-04-30 12:14:34 -0700281 fmt.Fprintf(w, "include $(CLEAR_VARS)\n")
282 fmt.Fprintf(w, "%s\n", strings.Join(props, "\n"))
283 fmt.Fprintf(w, "include $(%s)\n\n", moduleRule)
284}
Andres Moralesda8706f2015-04-29 12:46:49 -0700285
Colin Crossb0931242015-06-29 14:18:27 -0700286func (w *androidMkWriter) parsePropsAndWriteModule(module *Module) error {
Dan Willemsen3a4045d2015-06-24 15:37:17 -0700287 standardProps := make([]string, 0, len(module.bpmod.Properties))
Andres Moralesaf11df12015-04-30 12:14:34 -0700288 disabledBuilds := make(map[string]bool)
Dan Willemsen3a4045d2015-06-24 15:37:17 -0700289 for _, prop := range module.bpmod.Properties {
Colin Cross3cc00f12015-07-07 12:22:51 -0700290 if assignment, ok, err := translateSingleProperty(prop); err != nil {
291 return err
292 } else if ok {
293 standardProps = append(standardProps, assignment.assignment())
Andres Moralesaf11df12015-04-30 12:14:34 -0700294 } else if suffixMap, ok := suffixProperties[prop.Name.Name]; ok {
Colin Crossb3245e92015-06-30 16:27:57 -0700295 props, err := translateSuffixProperties(prop.Value.MapValue, suffixMap)
Colin Crossb0931242015-06-29 14:18:27 -0700296 if err != nil {
297 return err
298 }
299 standardProps = append(standardProps, props...)
Andres Moralesaf11df12015-04-30 12:14:34 -0700300 } else if "target" == prop.Name.Name {
Colin Crossb3245e92015-06-30 16:27:57 -0700301 props, err := translateTargetConditionals(prop.Value.MapValue, disabledBuilds, module.isHostRule)
Colin Crossb0931242015-06-29 14:18:27 -0700302 if err != nil {
303 return err
304 }
305 standardProps = append(standardProps, props...)
Dan Willemsen0a544692015-06-24 15:50:07 -0700306 } else if _, ok := ignoredProperties[prop.Name.Name]; ok {
Andres Moralesaf11df12015-04-30 12:14:34 -0700307 } else {
Colin Crossb0931242015-06-29 14:18:27 -0700308 return fmt.Errorf("Unsupported property %q", prop.Name.Name)
Andres Moralesaf11df12015-04-30 12:14:34 -0700309 }
310 }
311
Dan Willemsen3a4045d2015-06-24 15:37:17 -0700312 w.writeModule(module.mkname, standardProps, disabledBuilds, module.isHostRule)
Colin Crossb0931242015-06-29 14:18:27 -0700313
314 return nil
Dan Willemsen68fdfcc2015-06-11 14:05:01 -0700315}
316
Dan Willemsen26173162015-07-06 13:36:50 -0700317func canUseWholeStaticLibrary(m *Module) (bool, error) {
318 ret := true
319
320 isCompatible := func(props Properties, prop *bpparser.Property) error {
321 for _, p := range prop.Value.MapValue {
322 if p.Name.Name == "cflags" {
323 ret = false
324 return nil
325 }
326 if prop.Name.Name == "static" {
327 if p.Name.Name == "srcs" {
328 ret = false
329 return nil
330 }
331 }
332 }
333 return nil
334 }
335
336 err := m.IterateArchPropertiesWithName("shared", isCompatible)
337 if err != nil {
338 return false, err
339 }
340 err = m.IterateArchPropertiesWithName("static", isCompatible)
341 if err != nil {
342 return false, err
343 }
344
345 return ret, nil
346}
347
Colin Crossb0931242015-06-29 14:18:27 -0700348func (w *androidMkWriter) mutateModule(module *Module) (modules []*Module, err error) {
Dan Willemsen3a4045d2015-06-24 15:37:17 -0700349 modules = []*Module{module}
Dan Willemsen49f50452015-06-24 14:56:00 -0700350
Dan Willemsen3a4045d2015-06-24 15:37:17 -0700351 if module.bpname == "cc_library" {
352 modules = []*Module{
353 newModule(module.bpmod),
354 newModule(module.bpmod),
355 }
Dan Willemsen27012122015-06-26 17:40:54 -0700356
357 ccLinkageCopy := func(props Properties, prop *bpparser.Property) error {
358 for _, p := range prop.Value.MapValue {
359 err := props.AppendToProp(p.Name.Name, p)
360 if err != nil {
361 return err
362 }
363 }
364 props.DeleteProp(prop.Name.Name)
365 return nil
366 }
Dan Willemsen26173162015-07-06 13:36:50 -0700367 deleteProp := func(props Properties, prop *bpparser.Property) error {
Dan Willemsen27012122015-06-26 17:40:54 -0700368 props.DeleteProp(prop.Name.Name)
369 return nil
370 }
371
Dan Willemsen26173162015-07-06 13:36:50 -0700372 if ok, err := canUseWholeStaticLibrary(module); err != nil {
373 return nil, err
374 } else if ok {
375 err = modules[0].IterateArchPropertiesWithName("srcs", deleteProp)
376 if err != nil {
377 return nil, err
378 }
379
380 if nameProp, ok := modules[0].Properties().Prop("name"); !ok {
381 return nil, fmt.Errorf("Can't find name property")
382 } else {
383 modules[0].Properties().AppendToProp("whole_static_libs", &bpparser.Property{
384 Value: bpparser.Value{
385 Type: bpparser.List,
386 ListValue: []bpparser.Value{
387 nameProp.Value.Copy(),
388 },
389 },
390 })
391 }
392 }
393
Dan Willemsen3a4045d2015-06-24 15:37:17 -0700394 modules[0].bpname = "cc_library_shared"
Dan Willemsen27012122015-06-26 17:40:54 -0700395 err := modules[0].IterateArchPropertiesWithName("shared", ccLinkageCopy)
396 if err != nil {
397 return nil, err
398 }
Dan Willemsen26173162015-07-06 13:36:50 -0700399 err = modules[0].IterateArchPropertiesWithName("static", deleteProp)
Dan Willemsen27012122015-06-26 17:40:54 -0700400 if err != nil {
401 return nil, err
402 }
403
Dan Willemsen3a4045d2015-06-24 15:37:17 -0700404 modules[1].bpname = "cc_library_static"
Dan Willemsen26173162015-07-06 13:36:50 -0700405 err = modules[1].IterateArchPropertiesWithName("shared", deleteProp)
Dan Willemsen27012122015-06-26 17:40:54 -0700406 if err != nil {
407 return nil, err
408 }
409 err = modules[1].IterateArchPropertiesWithName("static", ccLinkageCopy)
410 if err != nil {
411 return nil, err
412 }
Dan Willemsen3a4045d2015-06-24 15:37:17 -0700413 }
414
415 for _, mod := range modules {
Colin Crossb0931242015-06-29 14:18:27 -0700416 err := mod.translateRuleName()
417 if err != nil {
418 return nil, err
419 }
Dan Willemsen27012122015-06-26 17:40:54 -0700420 if mod.isHostRule || !mod.PropBool("host_supported") {
Dan Willemsen3a4045d2015-06-24 15:37:17 -0700421 continue
422 }
423
424 m := &Module{
425 bpmod: mod.bpmod,
426 bpname: mod.bpname,
427 isHostRule: true,
428 }
Colin Crossb0931242015-06-29 14:18:27 -0700429 err = m.translateRuleName()
430 if err != nil {
431 return nil, err
432 }
Dan Willemsen3a4045d2015-06-24 15:37:17 -0700433 modules = append(modules, m)
Dan Willemsen68fdfcc2015-06-11 14:05:01 -0700434 }
435
Dan Willemsen49f50452015-06-24 14:56:00 -0700436 return
437}
Dan Willemsen68fdfcc2015-06-11 14:05:01 -0700438
Colin Crossb0931242015-06-29 14:18:27 -0700439func (w *androidMkWriter) handleModule(inputModule *bpparser.Module) error {
Colin Crossb1a66c02015-06-29 16:24:57 -0700440 comment := w.getCommentBlock(inputModule.Type.Pos)
441 if translation, translated, err := getCommentTranslation(comment); err != nil {
442 return err
443 } else if translated {
444 w.WriteString(translation)
445 return nil
446 }
447
Colin Cross70a5f072015-06-29 17:44:56 -0700448 if ignoredModuleType[inputModule.Type.Name] {
449 return nil
450 }
451
Colin Crossb0931242015-06-29 14:18:27 -0700452 modules, err := w.mutateModule(newModule(inputModule))
453 if err != nil {
454 return err
455 }
Dan Willemsen49f50452015-06-24 14:56:00 -0700456
457 for _, module := range modules {
Colin Crossb0931242015-06-29 14:18:27 -0700458 err := w.parsePropsAndWriteModule(module)
459 if err != nil {
460 return err
461 }
Andres Moralesaf11df12015-04-30 12:14:34 -0700462 }
Colin Crossb0931242015-06-29 14:18:27 -0700463
464 return nil
Andres Moralesaf11df12015-04-30 12:14:34 -0700465}
466
467func (w *androidMkWriter) handleSubdirs(value bpparser.Value) {
Andres Morales8ae47de2015-05-11 12:26:07 -0700468 subdirs := make([]string, 0, len(value.ListValue))
469 for _, tok := range value.ListValue {
470 subdirs = append(subdirs, tok.StringValue)
Andres Moralesda8706f2015-04-29 12:46:49 -0700471 }
Ying Wang38284902015-06-02 18:44:59 -0700472 // The current makefile may be generated to outside the source tree (such as the out directory), with a different structure.
473 fmt.Fprintf(w, "# Uncomment the following line if you really want to include subdir Android.mks.\n")
474 fmt.Fprintf(w, "# include $(wildcard $(addsuffix $(LOCAL_PATH)/%s/, Android.mk))\n", strings.Join(subdirs, " "))
Andres Moralesda8706f2015-04-29 12:46:49 -0700475}
476
Andres Morales8ae47de2015-05-11 12:26:07 -0700477func (w *androidMkWriter) handleLocalPath() error {
Colin Crossb3245e92015-06-30 16:27:57 -0700478 w.WriteString("LOCAL_PATH := " + w.path + "\n")
Dan Willemsenc2666e62015-06-10 16:18:58 -0700479 w.WriteString("LOCAL_MODULE_MAKEFILE := $(lastword $(MAKEFILE_LIST))\n\n")
Andres Morales8ae47de2015-05-11 12:26:07 -0700480 return nil
481}
482
Colin Crossb1a66c02015-06-29 16:24:57 -0700483// Returns any block comment on the line preceding pos as a string
484func (w *androidMkWriter) getCommentBlock(pos scanner.Position) string {
485 var buf []byte
486
487 comments := w.blueprint.Comments
488 for i, c := range comments {
489 if c.EndLine() == pos.Line-1 {
490 line := pos.Line
491 for j := i; j >= 0; j-- {
492 c = comments[j]
493 if c.EndLine() == line-1 {
494 buf = append([]byte(c.Text()), buf...)
495 line = c.Pos.Line
496 } else {
497 break
498 }
499 }
500 }
501 }
502
503 return string(buf)
504}
505
506func getCommentTranslation(comment string) (string, bool, error) {
507 lines := strings.Split(comment, "\n")
508
509 if directive, i, err := getCommentDirective(lines); err != nil {
510 return "", false, err
511 } else if directive != "" {
512 switch directive {
513 case "ignore":
514 return "", true, nil
515 case "start":
516 return getCommentTranslationBlock(lines[i+1:])
517 case "end":
518 return "", false, fmt.Errorf("Unexpected Android.mk:end translation directive")
519 default:
520 return "", false, fmt.Errorf("Unknown Android.mk module translation directive %q", directive)
521 }
522 }
523
524 return "", false, nil
525}
526
527func getCommentTranslationBlock(lines []string) (string, bool, error) {
528 var buf []byte
529
530 for _, line := range lines {
531 if directive := getLineCommentDirective(line); directive != "" {
532 switch directive {
533 case "end":
534 return string(buf), true, nil
535 default:
536 return "", false, fmt.Errorf("Unexpected Android.mk translation directive %q inside start", directive)
537 }
538 } else {
539 buf = append(buf, line...)
540 buf = append(buf, '\n')
541 }
542 }
543
544 return "", false, fmt.Errorf("Missing Android.mk:end translation directive")
545}
546
547func getCommentDirective(lines []string) (directive string, n int, err error) {
548 for i, line := range lines {
549 if directive := getLineCommentDirective(line); directive != "" {
550 return strings.ToLower(directive), i, nil
551 }
552 }
553
554 return "", -1, nil
555}
556
557func getLineCommentDirective(line string) string {
558 line = strings.TrimSpace(line)
559 if strings.HasPrefix(line, "Android.mk:") {
560 line = strings.TrimPrefix(line, "Android.mk:")
561 line = strings.TrimSpace(line)
562 return line
563 }
564
565 return ""
566}
567
Colin Crossb0931242015-06-29 14:18:27 -0700568func (w *androidMkWriter) write(writer io.Writer) (err error) {
569 w.Writer = writer
Andres Moralesda8706f2015-04-29 12:46:49 -0700570
Colin Crossb0931242015-06-29 14:18:27 -0700571 if err = w.handleLocalPath(); err != nil {
Colin Cross26478b72015-06-29 13:46:00 -0700572 return err
573 }
574
575 for _, block := range w.blueprint.Defs {
Andres Moralesda8706f2015-04-29 12:46:49 -0700576 switch block := block.(type) {
577 case *bpparser.Module:
Colin Crossb0931242015-06-29 14:18:27 -0700578 err = w.handleModule(block)
Andres Moralesda8706f2015-04-29 12:46:49 -0700579 case *bpparser.Assignment:
Colin Crossb3245e92015-06-30 16:27:57 -0700580 // Nothing
Colin Crossb0931242015-06-29 14:18:27 -0700581 default:
582 return fmt.Errorf("Unhandled def %v", block)
583 }
584 if err != nil {
585 return err
Andres Moralesda8706f2015-04-29 12:46:49 -0700586 }
587 }
588
Ying Wang38284902015-06-02 18:44:59 -0700589 return nil
Andres Moralesda8706f2015-04-29 12:46:49 -0700590}
591
Colin Crossb3245e92015-06-30 16:27:57 -0700592func translate(rootFile, androidBp, androidMk string) error {
Andres Moralesda8706f2015-04-29 12:46:49 -0700593
Colin Crossb3245e92015-06-30 16:27:57 -0700594 ctx := blueprint.NewContext()
595
596 var blueprintFile *bpparser.File
597
598 _, errs := ctx.WalkBlueprintsFiles(rootFile, func(file *bpparser.File) {
599 if file.Name == androidBp {
600 blueprintFile = file
601 }
602 })
Andres Moralesda8706f2015-04-29 12:46:49 -0700603 if len(errs) > 0 {
Colin Crossb0931242015-06-29 14:18:27 -0700604 return errs[0]
Andres Moralesda8706f2015-04-29 12:46:49 -0700605 }
606
Colin Crossb3245e92015-06-30 16:27:57 -0700607 if blueprintFile == nil {
608 return fmt.Errorf("File %q wasn't parsed from %q", androidBp, rootFile)
609 }
610
Andres Moralesda8706f2015-04-29 12:46:49 -0700611 writer := &androidMkWriter{
Colin Crossb3245e92015-06-30 16:27:57 -0700612 blueprint: blueprintFile,
Ying Wang38284902015-06-02 18:44:59 -0700613 path: path.Dir(androidBp),
Andres Moralesda8706f2015-04-29 12:46:49 -0700614 }
615
Colin Crossb0931242015-06-29 14:18:27 -0700616 buf := &bytes.Buffer{}
617
Colin Crossb3245e92015-06-30 16:27:57 -0700618 err := writer.write(buf)
Ying Wang38284902015-06-02 18:44:59 -0700619 if err != nil {
Colin Crossb0931242015-06-29 14:18:27 -0700620 os.Remove(androidMk)
621 return err
622 }
623
624 f, err := os.Create(androidMk)
625 if err != nil {
626 return err
627 }
628 defer f.Close()
629
630 _, err = f.Write(buf.Bytes())
631
632 return err
633}
634
635func main() {
Colin Crossb3245e92015-06-30 16:27:57 -0700636 if len(os.Args) < 4 {
637 fmt.Fprintln(os.Stderr, "Expected root Android.bp, input and output filename arguments")
Colin Crossb0931242015-06-29 14:18:27 -0700638 os.Exit(1)
639 }
640
Colin Crossb3245e92015-06-30 16:27:57 -0700641 rootFile := os.Args[1]
642 androidBp, err := filepath.Rel(filepath.Dir(rootFile), os.Args[2])
643 if err != nil {
644 fmt.Fprintf(os.Stderr, "Android.bp file %q is not relative to %q: %s\n",
645 os.Args[2], rootFile, err.Error())
646 os.Exit(1)
647 }
648 androidMk := os.Args[3]
Colin Crossb0931242015-06-29 14:18:27 -0700649
Colin Crossb3245e92015-06-30 16:27:57 -0700650 err = translate(rootFile, androidBp, androidMk)
Colin Crossb0931242015-06-29 14:18:27 -0700651 if err != nil {
652 fmt.Fprintf(os.Stderr, "Error translating %s: %s\n", androidBp, err.Error())
Ying Wang38284902015-06-02 18:44:59 -0700653 os.Exit(1)
654 }
Andres Moralesda8706f2015-04-29 12:46:49 -0700655}