blob: 5ab7788138c104142619e96304decfe31106d133 [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
178func translateSuffixProperties(suffixProps []*bpparser.Property,
Colin Crossb0931242015-06-29 14:18:27 -0700179 suffixMap map[string]string) (computedProps []string, err error) {
Andres Moralesaf11df12015-04-30 12:14:34 -0700180 for _, suffixProp := range suffixProps {
181 if suffix, ok := suffixMap[suffixProp.Name.Name]; ok {
182 for _, stdProp := range suffixProp.Value.MapValue {
Colin Cross3cc00f12015-07-07 12:22:51 -0700183 if assignment, ok, err := translateSingleProperty(stdProp); err != nil {
184 return nil, err
185 } else if ok {
186 computedProps = append(computedProps, assignment.assignmentWithSuffix(suffix))
Andres Moralesaf11df12015-04-30 12:14:34 -0700187 } else {
Colin Crossb0931242015-06-29 14:18:27 -0700188 return nil, fmt.Errorf("Unsupported property %q", stdProp.Name.Name)
Andres Moralesaf11df12015-04-30 12:14:34 -0700189 }
190 }
Colin Crossb0931242015-06-29 14:18:27 -0700191 } else {
192 return nil, fmt.Errorf("Unsupported suffix property %q", suffixProp.Name.Name)
Andres Moralesaf11df12015-04-30 12:14:34 -0700193 }
194 }
195 return
196}
197
Colin Cross3cc00f12015-07-07 12:22:51 -0700198func translateSingleProperty(prop *bpparser.Property) (propAssignment, bool, error) {
199 var assignment propAssignment
200 if mkProp, ok := standardProperties[prop.Name.Name]; ok {
201 name := mkProp.string
202 val, err := valueToString(prop.Value)
203 if err != nil {
204 return propAssignment{}, false, err
205 }
206 assignment = propAssignment{name, ":=", val}
207 } else if rwProp, ok := rewriteProperties[prop.Name.Name]; ok {
208 val, err := valueToString(prop.Value)
209 if err != nil {
210 return propAssignment{}, false, err
211 }
212 assignment, err = rwProp.f(rwProp.string, prop, val)
213 if err != nil {
214 return propAssignment{}, false, err
215 }
216 } else {
217 // Unhandled, return false with no error to tell the caller to handle it
218 return propAssignment{}, false, nil
Colin Crossc41f6302015-06-30 12:19:47 -0700219 }
Colin Cross3cc00f12015-07-07 12:22:51 -0700220 return assignment, true, nil
Colin Crossc41f6302015-06-30 12:19:47 -0700221}
222
Colin Cross3cc00f12015-07-07 12:22:51 -0700223func appendAssign(name string, prop *bpparser.Property, val string) (propAssignment, error) {
224 return propAssignment{name, "+=", val}, nil
Dan Willemsen57ad08c2015-06-10 16:20:14 -0700225}
226
Colin Cross3cc00f12015-07-07 12:22:51 -0700227func prependLocalPath(name string, prop *bpparser.Property, val string) (propAssignment, error) {
228 return propAssignment{name, "+=", fmt.Sprintf("$(addprefix $(LOCAL_PATH)/,%s)", val)}, nil
Dan Willemsen1d9f2792015-06-22 15:40:14 -0700229}
230
Colin Cross3cc00f12015-07-07 12:22:51 -0700231func prependLocalModule(name string, prop *bpparser.Property, val string) (propAssignment, error) {
232 return propAssignment{name, ":=", "$(LOCAL_MODULE)" + val}, nil
233}
234
235func versionScript(name string, prop *bpparser.Property, val string) (propAssignment, error) {
236 return propAssignment{name, "+=", "-Wl,--version-script,$(LOCAL_PATH)/" + val}, nil
Colin Crossaee540a2015-07-06 17:48:31 -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 {
Colin Cross3cc00f12015-07-07 12:22:51 -0700261 if assignment, ok, err := translateSingleProperty(prop); err != nil {
262 return err
263 } else if ok {
264 standardProps = append(standardProps, assignment.assignment())
Andres Moralesaf11df12015-04-30 12:14:34 -0700265 } else if suffixMap, ok := suffixProperties[prop.Name.Name]; ok {
Colin Crossb3245e92015-06-30 16:27:57 -0700266 props, err := translateSuffixProperties(prop.Value.MapValue, suffixMap)
Colin Crossb0931242015-06-29 14:18:27 -0700267 if err != nil {
268 return err
269 }
270 standardProps = append(standardProps, props...)
Andres Moralesaf11df12015-04-30 12:14:34 -0700271 } else if "target" == prop.Name.Name {
Colin Crossb3245e92015-06-30 16:27:57 -0700272 props, err := translateTargetConditionals(prop.Value.MapValue, disabledBuilds, module.isHostRule)
Colin Crossb0931242015-06-29 14:18:27 -0700273 if err != nil {
274 return err
275 }
276 standardProps = append(standardProps, props...)
Dan Willemsen0a544692015-06-24 15:50:07 -0700277 } else if _, ok := ignoredProperties[prop.Name.Name]; ok {
Andres Moralesaf11df12015-04-30 12:14:34 -0700278 } else {
Colin Crossb0931242015-06-29 14:18:27 -0700279 return fmt.Errorf("Unsupported property %q", prop.Name.Name)
Andres Moralesaf11df12015-04-30 12:14:34 -0700280 }
281 }
282
Dan Willemsen3a4045d2015-06-24 15:37:17 -0700283 w.writeModule(module.mkname, standardProps, disabledBuilds, module.isHostRule)
Colin Crossb0931242015-06-29 14:18:27 -0700284
285 return nil
Dan Willemsen68fdfcc2015-06-11 14:05:01 -0700286}
287
Dan Willemsen26173162015-07-06 13:36:50 -0700288func canUseWholeStaticLibrary(m *Module) (bool, error) {
289 ret := true
290
291 isCompatible := func(props Properties, prop *bpparser.Property) error {
292 for _, p := range prop.Value.MapValue {
293 if p.Name.Name == "cflags" {
294 ret = false
295 return nil
296 }
297 if prop.Name.Name == "static" {
298 if p.Name.Name == "srcs" {
299 ret = false
300 return nil
301 }
302 }
303 }
304 return nil
305 }
306
307 err := m.IterateArchPropertiesWithName("shared", isCompatible)
308 if err != nil {
309 return false, err
310 }
311 err = m.IterateArchPropertiesWithName("static", isCompatible)
312 if err != nil {
313 return false, err
314 }
315
316 return ret, nil
317}
318
Colin Crossb0931242015-06-29 14:18:27 -0700319func (w *androidMkWriter) mutateModule(module *Module) (modules []*Module, err error) {
Dan Willemsen3a4045d2015-06-24 15:37:17 -0700320 modules = []*Module{module}
Dan Willemsen49f50452015-06-24 14:56:00 -0700321
Dan Willemsen3a4045d2015-06-24 15:37:17 -0700322 if module.bpname == "cc_library" {
323 modules = []*Module{
324 newModule(module.bpmod),
325 newModule(module.bpmod),
326 }
Dan Willemsen27012122015-06-26 17:40:54 -0700327
328 ccLinkageCopy := func(props Properties, prop *bpparser.Property) error {
329 for _, p := range prop.Value.MapValue {
330 err := props.AppendToProp(p.Name.Name, p)
331 if err != nil {
332 return err
333 }
334 }
335 props.DeleteProp(prop.Name.Name)
336 return nil
337 }
Dan Willemsen26173162015-07-06 13:36:50 -0700338 deleteProp := func(props Properties, prop *bpparser.Property) error {
Dan Willemsen27012122015-06-26 17:40:54 -0700339 props.DeleteProp(prop.Name.Name)
340 return nil
341 }
342
Dan Willemsen26173162015-07-06 13:36:50 -0700343 if ok, err := canUseWholeStaticLibrary(module); err != nil {
344 return nil, err
345 } else if ok {
346 err = modules[0].IterateArchPropertiesWithName("srcs", deleteProp)
347 if err != nil {
348 return nil, err
349 }
350
351 if nameProp, ok := modules[0].Properties().Prop("name"); !ok {
352 return nil, fmt.Errorf("Can't find name property")
353 } else {
354 modules[0].Properties().AppendToProp("whole_static_libs", &bpparser.Property{
355 Value: bpparser.Value{
356 Type: bpparser.List,
357 ListValue: []bpparser.Value{
358 nameProp.Value.Copy(),
359 },
360 },
361 })
362 }
363 }
364
Dan Willemsen3a4045d2015-06-24 15:37:17 -0700365 modules[0].bpname = "cc_library_shared"
Dan Willemsen27012122015-06-26 17:40:54 -0700366 err := modules[0].IterateArchPropertiesWithName("shared", ccLinkageCopy)
367 if err != nil {
368 return nil, err
369 }
Dan Willemsen26173162015-07-06 13:36:50 -0700370 err = modules[0].IterateArchPropertiesWithName("static", deleteProp)
Dan Willemsen27012122015-06-26 17:40:54 -0700371 if err != nil {
372 return nil, err
373 }
374
Dan Willemsen3a4045d2015-06-24 15:37:17 -0700375 modules[1].bpname = "cc_library_static"
Dan Willemsen26173162015-07-06 13:36:50 -0700376 err = modules[1].IterateArchPropertiesWithName("shared", deleteProp)
Dan Willemsen27012122015-06-26 17:40:54 -0700377 if err != nil {
378 return nil, err
379 }
380 err = modules[1].IterateArchPropertiesWithName("static", ccLinkageCopy)
381 if err != nil {
382 return nil, err
383 }
Dan Willemsen3a4045d2015-06-24 15:37:17 -0700384 }
385
386 for _, mod := range modules {
Colin Crossb0931242015-06-29 14:18:27 -0700387 err := mod.translateRuleName()
388 if err != nil {
389 return nil, err
390 }
Dan Willemsen27012122015-06-26 17:40:54 -0700391 if mod.isHostRule || !mod.PropBool("host_supported") {
Dan Willemsen3a4045d2015-06-24 15:37:17 -0700392 continue
393 }
394
395 m := &Module{
396 bpmod: mod.bpmod,
397 bpname: mod.bpname,
398 isHostRule: true,
399 }
Colin Crossb0931242015-06-29 14:18:27 -0700400 err = m.translateRuleName()
401 if err != nil {
402 return nil, err
403 }
Dan Willemsen3a4045d2015-06-24 15:37:17 -0700404 modules = append(modules, m)
Dan Willemsen68fdfcc2015-06-11 14:05:01 -0700405 }
406
Dan Willemsen49f50452015-06-24 14:56:00 -0700407 return
408}
Dan Willemsen68fdfcc2015-06-11 14:05:01 -0700409
Colin Crossb0931242015-06-29 14:18:27 -0700410func (w *androidMkWriter) handleModule(inputModule *bpparser.Module) error {
Colin Crossb1a66c02015-06-29 16:24:57 -0700411 comment := w.getCommentBlock(inputModule.Type.Pos)
412 if translation, translated, err := getCommentTranslation(comment); err != nil {
413 return err
414 } else if translated {
415 w.WriteString(translation)
416 return nil
417 }
418
Colin Cross70a5f072015-06-29 17:44:56 -0700419 if ignoredModuleType[inputModule.Type.Name] {
420 return nil
421 }
422
Colin Crossb0931242015-06-29 14:18:27 -0700423 modules, err := w.mutateModule(newModule(inputModule))
424 if err != nil {
425 return err
426 }
Dan Willemsen49f50452015-06-24 14:56:00 -0700427
428 for _, module := range modules {
Colin Crossb0931242015-06-29 14:18:27 -0700429 err := w.parsePropsAndWriteModule(module)
430 if err != nil {
431 return err
432 }
Andres Moralesaf11df12015-04-30 12:14:34 -0700433 }
Colin Crossb0931242015-06-29 14:18:27 -0700434
435 return nil
Andres Moralesaf11df12015-04-30 12:14:34 -0700436}
437
438func (w *androidMkWriter) handleSubdirs(value bpparser.Value) {
Andres Morales8ae47de2015-05-11 12:26:07 -0700439 subdirs := make([]string, 0, len(value.ListValue))
440 for _, tok := range value.ListValue {
441 subdirs = append(subdirs, tok.StringValue)
Andres Moralesda8706f2015-04-29 12:46:49 -0700442 }
Ying Wang38284902015-06-02 18:44:59 -0700443 // The current makefile may be generated to outside the source tree (such as the out directory), with a different structure.
444 fmt.Fprintf(w, "# Uncomment the following line if you really want to include subdir Android.mks.\n")
445 fmt.Fprintf(w, "# include $(wildcard $(addsuffix $(LOCAL_PATH)/%s/, Android.mk))\n", strings.Join(subdirs, " "))
Andres Moralesda8706f2015-04-29 12:46:49 -0700446}
447
Andres Morales8ae47de2015-05-11 12:26:07 -0700448func (w *androidMkWriter) handleLocalPath() error {
Colin Crossb3245e92015-06-30 16:27:57 -0700449 w.WriteString("LOCAL_PATH := " + w.path + "\n")
Dan Willemsenc2666e62015-06-10 16:18:58 -0700450 w.WriteString("LOCAL_MODULE_MAKEFILE := $(lastword $(MAKEFILE_LIST))\n\n")
Andres Morales8ae47de2015-05-11 12:26:07 -0700451 return nil
452}
453
Colin Crossb1a66c02015-06-29 16:24:57 -0700454// Returns any block comment on the line preceding pos as a string
455func (w *androidMkWriter) getCommentBlock(pos scanner.Position) string {
456 var buf []byte
457
458 comments := w.blueprint.Comments
459 for i, c := range comments {
460 if c.EndLine() == pos.Line-1 {
461 line := pos.Line
462 for j := i; j >= 0; j-- {
463 c = comments[j]
464 if c.EndLine() == line-1 {
465 buf = append([]byte(c.Text()), buf...)
466 line = c.Pos.Line
467 } else {
468 break
469 }
470 }
471 }
472 }
473
474 return string(buf)
475}
476
477func getCommentTranslation(comment string) (string, bool, error) {
478 lines := strings.Split(comment, "\n")
479
480 if directive, i, err := getCommentDirective(lines); err != nil {
481 return "", false, err
482 } else if directive != "" {
483 switch directive {
484 case "ignore":
485 return "", true, nil
486 case "start":
487 return getCommentTranslationBlock(lines[i+1:])
488 case "end":
489 return "", false, fmt.Errorf("Unexpected Android.mk:end translation directive")
490 default:
491 return "", false, fmt.Errorf("Unknown Android.mk module translation directive %q", directive)
492 }
493 }
494
495 return "", false, nil
496}
497
498func getCommentTranslationBlock(lines []string) (string, bool, error) {
499 var buf []byte
500
501 for _, line := range lines {
502 if directive := getLineCommentDirective(line); directive != "" {
503 switch directive {
504 case "end":
505 return string(buf), true, nil
506 default:
507 return "", false, fmt.Errorf("Unexpected Android.mk translation directive %q inside start", directive)
508 }
509 } else {
510 buf = append(buf, line...)
511 buf = append(buf, '\n')
512 }
513 }
514
515 return "", false, fmt.Errorf("Missing Android.mk:end translation directive")
516}
517
518func getCommentDirective(lines []string) (directive string, n int, err error) {
519 for i, line := range lines {
520 if directive := getLineCommentDirective(line); directive != "" {
521 return strings.ToLower(directive), i, nil
522 }
523 }
524
525 return "", -1, nil
526}
527
528func getLineCommentDirective(line string) string {
529 line = strings.TrimSpace(line)
530 if strings.HasPrefix(line, "Android.mk:") {
531 line = strings.TrimPrefix(line, "Android.mk:")
532 line = strings.TrimSpace(line)
533 return line
534 }
535
536 return ""
537}
538
Colin Crossb0931242015-06-29 14:18:27 -0700539func (w *androidMkWriter) write(writer io.Writer) (err error) {
540 w.Writer = writer
Andres Moralesda8706f2015-04-29 12:46:49 -0700541
Colin Crossb0931242015-06-29 14:18:27 -0700542 if err = w.handleLocalPath(); err != nil {
Colin Cross26478b72015-06-29 13:46:00 -0700543 return err
544 }
545
546 for _, block := range w.blueprint.Defs {
Andres Moralesda8706f2015-04-29 12:46:49 -0700547 switch block := block.(type) {
548 case *bpparser.Module:
Colin Crossb0931242015-06-29 14:18:27 -0700549 err = w.handleModule(block)
Andres Moralesda8706f2015-04-29 12:46:49 -0700550 case *bpparser.Assignment:
Colin Crossb3245e92015-06-30 16:27:57 -0700551 // Nothing
Colin Crossb0931242015-06-29 14:18:27 -0700552 default:
553 return fmt.Errorf("Unhandled def %v", block)
554 }
555 if err != nil {
556 return err
Andres Moralesda8706f2015-04-29 12:46:49 -0700557 }
558 }
559
Ying Wang38284902015-06-02 18:44:59 -0700560 return nil
Andres Moralesda8706f2015-04-29 12:46:49 -0700561}
562
Colin Crossb3245e92015-06-30 16:27:57 -0700563func translate(rootFile, androidBp, androidMk string) error {
Andres Moralesda8706f2015-04-29 12:46:49 -0700564
Colin Crossb3245e92015-06-30 16:27:57 -0700565 ctx := blueprint.NewContext()
566
567 var blueprintFile *bpparser.File
568
569 _, errs := ctx.WalkBlueprintsFiles(rootFile, func(file *bpparser.File) {
570 if file.Name == androidBp {
571 blueprintFile = file
572 }
573 })
Andres Moralesda8706f2015-04-29 12:46:49 -0700574 if len(errs) > 0 {
Colin Crossb0931242015-06-29 14:18:27 -0700575 return errs[0]
Andres Moralesda8706f2015-04-29 12:46:49 -0700576 }
577
Colin Crossb3245e92015-06-30 16:27:57 -0700578 if blueprintFile == nil {
579 return fmt.Errorf("File %q wasn't parsed from %q", androidBp, rootFile)
580 }
581
Andres Moralesda8706f2015-04-29 12:46:49 -0700582 writer := &androidMkWriter{
Colin Crossb3245e92015-06-30 16:27:57 -0700583 blueprint: blueprintFile,
Ying Wang38284902015-06-02 18:44:59 -0700584 path: path.Dir(androidBp),
Andres Moralesda8706f2015-04-29 12:46:49 -0700585 }
586
Colin Crossb0931242015-06-29 14:18:27 -0700587 buf := &bytes.Buffer{}
588
Colin Crossb3245e92015-06-30 16:27:57 -0700589 err := writer.write(buf)
Ying Wang38284902015-06-02 18:44:59 -0700590 if err != nil {
Colin Crossb0931242015-06-29 14:18:27 -0700591 os.Remove(androidMk)
592 return err
593 }
594
595 f, err := os.Create(androidMk)
596 if err != nil {
597 return err
598 }
599 defer f.Close()
600
601 _, err = f.Write(buf.Bytes())
602
603 return err
604}
605
606func main() {
Colin Crossb3245e92015-06-30 16:27:57 -0700607 if len(os.Args) < 4 {
608 fmt.Fprintln(os.Stderr, "Expected root Android.bp, input and output filename arguments")
Colin Crossb0931242015-06-29 14:18:27 -0700609 os.Exit(1)
610 }
611
Colin Crossb3245e92015-06-30 16:27:57 -0700612 rootFile := os.Args[1]
613 androidBp, err := filepath.Rel(filepath.Dir(rootFile), os.Args[2])
614 if err != nil {
615 fmt.Fprintf(os.Stderr, "Android.bp file %q is not relative to %q: %s\n",
616 os.Args[2], rootFile, err.Error())
617 os.Exit(1)
618 }
619 androidMk := os.Args[3]
Colin Crossb0931242015-06-29 14:18:27 -0700620
Colin Crossb3245e92015-06-30 16:27:57 -0700621 err = translate(rootFile, androidBp, androidMk)
Colin Crossb0931242015-06-29 14:18:27 -0700622 if err != nil {
623 fmt.Fprintf(os.Stderr, "Error translating %s: %s\n", androidBp, err.Error())
Ying Wang38284902015-06-02 18:44:59 -0700624 os.Exit(1)
625 }
Andres Moralesda8706f2015-04-29 12:46:49 -0700626}