blob: abbaf4bf3f5a9a75512b7a437817f891ec82c5d4 [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
15 bpparser "github.com/google/blueprint/parser"
16)
17
Andres Morales8ae47de2015-05-11 12:26:07 -070018var recursiveSubdirRegex *regexp.Regexp = regexp.MustCompile("(.+)/\\*\\*/(.+)")
19
Dan Willemsen3a4045d2015-06-24 15:37:17 -070020type Module struct {
21 bpmod *bpparser.Module
22 bpname string
23 mkname string
24 isHostRule bool
25}
26
27func newModule(mod *bpparser.Module) *Module {
28 return &Module{
29 bpmod: mod,
30 bpname: mod.Type.Name,
31 }
32}
33
Colin Crossb0931242015-06-29 14:18:27 -070034func (m *Module) translateRuleName() error {
35 var name string
Dan Willemsen3a4045d2015-06-24 15:37:17 -070036 if translation, ok := moduleTypeToRule[m.bpname]; ok {
37 name = translation
Colin Crossb0931242015-06-29 14:18:27 -070038 } else {
39 return fmt.Errorf("Unknown module type %q", m.bpname)
Dan Willemsen3a4045d2015-06-24 15:37:17 -070040 }
41
42 if m.isHostRule {
43 if trans, ok := targetToHostModuleRule[name]; ok {
44 name = trans
45 } else {
Colin Crossb0931242015-06-29 14:18:27 -070046 return fmt.Errorf("No corresponding host rule for %q", name)
Dan Willemsen3a4045d2015-06-24 15:37:17 -070047 }
48 } else {
49 m.isHostRule = strings.Contains(name, "HOST")
50 }
51
52 m.mkname = name
Colin Crossb0931242015-06-29 14:18:27 -070053
54 return nil
Dan Willemsen3a4045d2015-06-24 15:37:17 -070055}
56
Andres Moralesda8706f2015-04-29 12:46:49 -070057type androidMkWriter struct {
Colin Crossb0931242015-06-29 14:18:27 -070058 io.Writer
Andres Moralesda8706f2015-04-29 12:46:49 -070059
Andres Moralesaf11df12015-04-30 12:14:34 -070060 blueprint *bpparser.File
61 path string
62
Dan Willemsen360a39c2015-06-11 14:34:50 -070063 printedLocalPath bool
64
Andres Moralesaf11df12015-04-30 12:14:34 -070065 mapScope map[string][]*bpparser.Property
Andres Moralesda8706f2015-04-29 12:46:49 -070066}
67
Colin Crossb0931242015-06-29 14:18:27 -070068func (w *androidMkWriter) WriteString(s string) (int, error) {
69 return io.WriteString(w.Writer, s)
70}
71
72func valueToString(value bpparser.Value) (string, error) {
Andres Moralesda8706f2015-04-29 12:46:49 -070073 if value.Variable != "" {
Colin Crossb0931242015-06-29 14:18:27 -070074 return fmt.Sprintf("$(%s)", value.Variable), nil
Colin Crossff3b7952015-06-22 15:39:35 -070075 } else if value.Expression != nil {
76 if value.Expression.Operator != '+' {
Colin Crossb0931242015-06-29 14:18:27 -070077 return "", fmt.Errorf("unexpected operator '%c'", value.Expression.Operator)
Colin Crossff3b7952015-06-22 15:39:35 -070078 }
Colin Crossb0931242015-06-29 14:18:27 -070079 val1, err := valueToString(value.Expression.Args[0])
80 if err != nil {
81 return "", err
82 }
83 val2, err := valueToString(value.Expression.Args[1])
84 if err != nil {
85 return "", err
86 }
87 return fmt.Sprintf("%s%s", val1, val2), nil
Andres Moralesda8706f2015-04-29 12:46:49 -070088 } else {
89 switch value.Type {
90 case bpparser.Bool:
Colin Crossb0931242015-06-29 14:18:27 -070091 return fmt.Sprintf("%t", value.BoolValue), nil
Andres Moralesda8706f2015-04-29 12:46:49 -070092 case bpparser.String:
Colin Crossb0931242015-06-29 14:18:27 -070093 return fmt.Sprintf("%s", processWildcards(value.StringValue)), nil
Andres Moralesda8706f2015-04-29 12:46:49 -070094 case bpparser.List:
Colin Crossb0931242015-06-29 14:18:27 -070095 val, err := listToMkString(value.ListValue)
96 if err != nil {
97 return "", err
98 }
99 return fmt.Sprintf("\\\n%s", val), nil
Andres Moralesda8706f2015-04-29 12:46:49 -0700100 case bpparser.Map:
Colin Crossb0931242015-06-29 14:18:27 -0700101 return "", fmt.Errorf("Can't convert map to string")
Andres Moralesaf11df12015-04-30 12:14:34 -0700102 default:
Colin Crossb0931242015-06-29 14:18:27 -0700103 return "", fmt.Errorf("ERROR: unsupported type %d", value.Type)
Andres Moralesda8706f2015-04-29 12:46:49 -0700104 }
105 }
Andres Moralesda8706f2015-04-29 12:46:49 -0700106}
107
Andres Morales8ae47de2015-05-11 12:26:07 -0700108func getTopOfAndroidTree(wd string) (string, error) {
109 if !filepath.IsAbs(wd) {
110 return "", errors.New("path must be absolute: " + wd)
111 }
112
113 topfile := "build/soong/bootstrap.bash"
114
115 for "/" != wd {
116 expected := filepath.Join(wd, topfile)
117
118 if _, err := os.Stat(expected); err == nil {
119 // Found the top
120 return wd, nil
121 }
122
123 wd = filepath.Join(wd, "..")
124 }
125
126 return "", errors.New("couldn't find top of tree from " + wd)
127}
128
Andres Moralesaf11df12015-04-30 12:14:34 -0700129// TODO: handle non-recursive wildcards?
130func processWildcards(s string) string {
Andres Morales8ae47de2015-05-11 12:26:07 -0700131 submatches := recursiveSubdirRegex.FindStringSubmatch(s)
132 if len(submatches) > 2 {
Andres Moralesaf11df12015-04-30 12:14:34 -0700133 // Found a wildcard rule
134 return fmt.Sprintf("$(call find-files-in-subdirs, $(LOCAL_PATH), %s, %s)",
Andres Morales8ae47de2015-05-11 12:26:07 -0700135 submatches[2], submatches[1])
Andres Moralesaf11df12015-04-30 12:14:34 -0700136 }
137
138 return s
139}
140
Colin Crossb0931242015-06-29 14:18:27 -0700141func listToMkString(list []bpparser.Value) (string, error) {
Andres Moralesda8706f2015-04-29 12:46:49 -0700142 lines := make([]string, 0, len(list))
143 for _, tok := range list {
Colin Crossb0931242015-06-29 14:18:27 -0700144 val, err := valueToString(tok)
145 if err != nil {
146 return "", err
147 }
148 lines = append(lines, fmt.Sprintf(" %s", val))
Andres Moralesda8706f2015-04-29 12:46:49 -0700149 }
150
Colin Crossb0931242015-06-29 14:18:27 -0700151 return strings.Join(lines, " \\\n"), nil
Andres Moralesda8706f2015-04-29 12:46:49 -0700152}
153
Andres Moralesaf11df12015-04-30 12:14:34 -0700154func translateTargetConditionals(props []*bpparser.Property,
Colin Crossb0931242015-06-29 14:18:27 -0700155 disabledBuilds map[string]bool, isHostRule bool) (computedProps []string, err error) {
Andres Moralesaf11df12015-04-30 12:14:34 -0700156 for _, target := range props {
157 conditionals := targetScopedPropertyConditionals
Dan Willemsen68fdfcc2015-06-11 14:05:01 -0700158 altConditionals := hostScopedPropertyConditionals
Andres Moralesaf11df12015-04-30 12:14:34 -0700159 if isHostRule {
Dan Willemsen68fdfcc2015-06-11 14:05:01 -0700160 conditionals, altConditionals = altConditionals, conditionals
Andres Moralesaf11df12015-04-30 12:14:34 -0700161 }
162
163 conditional, ok := conditionals[target.Name.Name]
164 if !ok {
Dan Willemsen68fdfcc2015-06-11 14:05:01 -0700165 if _, ok := altConditionals[target.Name.Name]; ok {
166 // This is only for the other build type
167 continue
168 } else {
Colin Crossb0931242015-06-29 14:18:27 -0700169 return nil, fmt.Errorf("Unsupported conditional %q", target.Name.Name)
Dan Willemsen68fdfcc2015-06-11 14:05:01 -0700170 }
Andres Moralesaf11df12015-04-30 12:14:34 -0700171 }
172
173 var scopedProps []string
174 for _, targetScopedProp := range target.Value.MapValue {
175 if mkProp, ok := standardProperties[targetScopedProp.Name.Name]; ok {
Colin Crossb0931242015-06-29 14:18:27 -0700176 val, err := valueToString(targetScopedProp.Value)
177 if err != nil {
178 return nil, err
179 }
Andres Moralesaf11df12015-04-30 12:14:34 -0700180 scopedProps = append(scopedProps, fmt.Sprintf("%s += %s",
Colin Crossb0931242015-06-29 14:18:27 -0700181 mkProp.string, val))
Dan Willemsen57ad08c2015-06-10 16:20:14 -0700182 } else if rwProp, ok := rewriteProperties[targetScopedProp.Name.Name]; ok {
Colin Crossb0931242015-06-29 14:18:27 -0700183 props, err := rwProp.f(rwProp.string, targetScopedProp, nil)
184 if err != nil {
185 return nil, err
186 }
187 scopedProps = append(scopedProps, props...)
Andres Moralesaf11df12015-04-30 12:14:34 -0700188 } else if "disabled" == targetScopedProp.Name.Name {
189 if targetScopedProp.Value.BoolValue {
190 disabledBuilds[target.Name.Name] = true
191 } else {
192 delete(disabledBuilds, target.Name.Name)
193 }
Colin Crossb0931242015-06-29 14:18:27 -0700194 } else {
195 return nil, fmt.Errorf("Unsupported target property %q", targetScopedProp.Name.Name)
Andres Moralesaf11df12015-04-30 12:14:34 -0700196 }
197 }
198
199 if len(scopedProps) > 0 {
Dan Willemsen68fdfcc2015-06-11 14:05:01 -0700200 if conditional != "" {
201 computedProps = append(computedProps, conditional)
202 computedProps = append(computedProps, scopedProps...)
203 computedProps = append(computedProps, "endif")
204 } else {
205 computedProps = append(computedProps, scopedProps...)
206 }
Andres Moralesaf11df12015-04-30 12:14:34 -0700207 }
Andres Moralesda8706f2015-04-29 12:46:49 -0700208 }
Andres Moralesaf11df12015-04-30 12:14:34 -0700209
210 return
211}
212
213func translateSuffixProperties(suffixProps []*bpparser.Property,
Colin Crossb0931242015-06-29 14:18:27 -0700214 suffixMap map[string]string) (computedProps []string, err error) {
Andres Moralesaf11df12015-04-30 12:14:34 -0700215 for _, suffixProp := range suffixProps {
216 if suffix, ok := suffixMap[suffixProp.Name.Name]; ok {
217 for _, stdProp := range suffixProp.Value.MapValue {
218 if mkProp, ok := standardProperties[stdProp.Name.Name]; ok {
Colin Crossb0931242015-06-29 14:18:27 -0700219 val, err := valueToString(stdProp.Value)
220 if err != nil {
221 return nil, err
222 }
223 computedProps = append(computedProps, fmt.Sprintf("%s_%s := %s", mkProp.string, suffix, val))
Dan Willemsen57ad08c2015-06-10 16:20:14 -0700224 } else if rwProp, ok := rewriteProperties[stdProp.Name.Name]; ok {
Colin Crossb0931242015-06-29 14:18:27 -0700225 props, err := rwProp.f(rwProp.string, stdProp, &suffix)
226 if err != nil {
227 return nil, err
228 }
229 computedProps = append(computedProps, props...)
Andres Moralesaf11df12015-04-30 12:14:34 -0700230 } else {
Colin Crossb0931242015-06-29 14:18:27 -0700231 return nil, fmt.Errorf("Unsupported property %q", stdProp.Name.Name)
Andres Moralesaf11df12015-04-30 12:14:34 -0700232 }
233 }
Colin Crossb0931242015-06-29 14:18:27 -0700234 } else {
235 return nil, fmt.Errorf("Unsupported suffix property %q", suffixProp.Name.Name)
Andres Moralesaf11df12015-04-30 12:14:34 -0700236 }
237 }
238 return
239}
240
Colin Crossb0931242015-06-29 14:18:27 -0700241func prependLocalPath(name string, prop *bpparser.Property, suffix *string) ([]string, error) {
Dan Willemsen57ad08c2015-06-10 16:20:14 -0700242 if suffix != nil {
243 name += "_" + *suffix
244 }
Colin Crossb0931242015-06-29 14:18:27 -0700245 val, err := valueToString(prop.Value)
246 if err != nil {
247 return nil, err
248 }
Colin Crossff3b7952015-06-22 15:39:35 -0700249 return []string{
Colin Crossb0931242015-06-29 14:18:27 -0700250 fmt.Sprintf("%s := $(addprefix $(LOCAL_PATH)/,%s)\n", name, val),
251 }, nil
Dan Willemsen57ad08c2015-06-10 16:20:14 -0700252}
253
Colin Crossb0931242015-06-29 14:18:27 -0700254func prependLocalModule(name string, prop *bpparser.Property, suffix *string) ([]string, error) {
Dan Willemsen1d9f2792015-06-22 15:40:14 -0700255 if suffix != nil {
256 name += "_" + *suffix
257 }
Colin Crossb0931242015-06-29 14:18:27 -0700258 val, err := valueToString(prop.Value)
259 if err != nil {
260 return nil, err
Dan Willemsen1d9f2792015-06-22 15:40:14 -0700261 }
Colin Crossb0931242015-06-29 14:18:27 -0700262 return []string{
263 fmt.Sprintf("%s := $(LOCAL_MODULE)%s\n", name, val),
264 }, nil
Dan Willemsen1d9f2792015-06-22 15:40:14 -0700265}
266
Dan Willemsen3a4045d2015-06-24 15:37:17 -0700267func modulePropBool(module *bpparser.Module, name string) bool {
268 for _, prop := range module.Properties {
269 if name == prop.Name.Name {
270 return prop.Value.BoolValue
271 }
272 }
273 return false
274}
275
Andres Moralesaf11df12015-04-30 12:14:34 -0700276func (w *androidMkWriter) lookupMap(parent bpparser.Value) (mapValue []*bpparser.Property) {
277 if parent.Variable != "" {
278 mapValue = w.mapScope[parent.Variable]
279 } else {
280 mapValue = parent.MapValue
281 }
282 return
Andres Moralesda8706f2015-04-29 12:46:49 -0700283}
284
Andres Moralesaf11df12015-04-30 12:14:34 -0700285func (w *androidMkWriter) writeModule(moduleRule string, props []string,
286 disabledBuilds map[string]bool, isHostRule bool) {
287 disabledConditionals := disabledTargetConditionals
288 if isHostRule {
289 disabledConditionals = disabledHostConditionals
290 }
291 for build, _ := range disabledBuilds {
292 if conditional, ok := disabledConditionals[build]; ok {
293 fmt.Fprintf(w, "%s\n", conditional)
294 defer fmt.Fprintf(w, "endif\n")
Andres Moralesda8706f2015-04-29 12:46:49 -0700295 }
Andres Moralesaf11df12015-04-30 12:14:34 -0700296 }
Andres Moralesda8706f2015-04-29 12:46:49 -0700297
Andres Moralesaf11df12015-04-30 12:14:34 -0700298 fmt.Fprintf(w, "include $(CLEAR_VARS)\n")
299 fmt.Fprintf(w, "%s\n", strings.Join(props, "\n"))
300 fmt.Fprintf(w, "include $(%s)\n\n", moduleRule)
301}
Andres Moralesda8706f2015-04-29 12:46:49 -0700302
Colin Crossb0931242015-06-29 14:18:27 -0700303func (w *androidMkWriter) parsePropsAndWriteModule(module *Module) error {
Dan Willemsen3a4045d2015-06-24 15:37:17 -0700304 standardProps := make([]string, 0, len(module.bpmod.Properties))
Andres Moralesaf11df12015-04-30 12:14:34 -0700305 disabledBuilds := make(map[string]bool)
Dan Willemsen3a4045d2015-06-24 15:37:17 -0700306 for _, prop := range module.bpmod.Properties {
Andres Moralesaf11df12015-04-30 12:14:34 -0700307 if mkProp, ok := standardProperties[prop.Name.Name]; ok {
Colin Crossb0931242015-06-29 14:18:27 -0700308 val, err := valueToString(prop.Value)
309 if err != nil {
310 return err
311 }
312 standardProps = append(standardProps, fmt.Sprintf("%s := %s", mkProp.string, val))
Dan Willemsen57ad08c2015-06-10 16:20:14 -0700313 } else if rwProp, ok := rewriteProperties[prop.Name.Name]; ok {
Colin Crossb0931242015-06-29 14:18:27 -0700314 props, err := rwProp.f(rwProp.string, prop, nil)
315 if err != nil {
316 return err
317 }
318 standardProps = append(standardProps, props...)
Andres Moralesaf11df12015-04-30 12:14:34 -0700319 } else if suffixMap, ok := suffixProperties[prop.Name.Name]; ok {
320 suffixProps := w.lookupMap(prop.Value)
Colin Crossb0931242015-06-29 14:18:27 -0700321 props, err := translateSuffixProperties(suffixProps, suffixMap)
322 if err != nil {
323 return err
324 }
325 standardProps = append(standardProps, props...)
Andres Moralesaf11df12015-04-30 12:14:34 -0700326 } else if "target" == prop.Name.Name {
Colin Crossb0931242015-06-29 14:18:27 -0700327 suffixProps := w.lookupMap(prop.Value)
328 props, err := translateTargetConditionals(suffixProps, disabledBuilds, module.isHostRule)
329 if err != nil {
330 return err
331 }
332 standardProps = append(standardProps, props...)
Dan Willemsen0a544692015-06-24 15:50:07 -0700333 } else if _, ok := ignoredProperties[prop.Name.Name]; ok {
Andres Moralesaf11df12015-04-30 12:14:34 -0700334 } else {
Colin Crossb0931242015-06-29 14:18:27 -0700335 return fmt.Errorf("Unsupported property %q", prop.Name.Name)
Andres Moralesaf11df12015-04-30 12:14:34 -0700336 }
337 }
338
Dan Willemsen3a4045d2015-06-24 15:37:17 -0700339 w.writeModule(module.mkname, standardProps, disabledBuilds, module.isHostRule)
Colin Crossb0931242015-06-29 14:18:27 -0700340
341 return nil
Dan Willemsen68fdfcc2015-06-11 14:05:01 -0700342}
343
Colin Crossb0931242015-06-29 14:18:27 -0700344func (w *androidMkWriter) mutateModule(module *Module) (modules []*Module, err error) {
Dan Willemsen3a4045d2015-06-24 15:37:17 -0700345 modules = []*Module{module}
Dan Willemsen49f50452015-06-24 14:56:00 -0700346
Dan Willemsen3a4045d2015-06-24 15:37:17 -0700347 if module.bpname == "cc_library" {
348 modules = []*Module{
349 newModule(module.bpmod),
350 newModule(module.bpmod),
351 }
352 modules[0].bpname = "cc_library_shared"
353 modules[1].bpname = "cc_library_static"
354 }
355
356 for _, mod := range modules {
Colin Crossb0931242015-06-29 14:18:27 -0700357 err := mod.translateRuleName()
358 if err != nil {
359 return nil, err
360 }
Dan Willemsen3a4045d2015-06-24 15:37:17 -0700361 if mod.isHostRule || !modulePropBool(mod.bpmod, "host_supported") {
362 continue
363 }
364
365 m := &Module{
366 bpmod: mod.bpmod,
367 bpname: mod.bpname,
368 isHostRule: true,
369 }
Colin Crossb0931242015-06-29 14:18:27 -0700370 err = m.translateRuleName()
371 if err != nil {
372 return nil, err
373 }
Dan Willemsen3a4045d2015-06-24 15:37:17 -0700374 modules = append(modules, m)
Dan Willemsen68fdfcc2015-06-11 14:05:01 -0700375 }
376
Dan Willemsen49f50452015-06-24 14:56:00 -0700377 return
378}
Dan Willemsen68fdfcc2015-06-11 14:05:01 -0700379
Colin Crossb0931242015-06-29 14:18:27 -0700380func (w *androidMkWriter) handleModule(inputModule *bpparser.Module) error {
Colin Crossb1a66c02015-06-29 16:24:57 -0700381 comment := w.getCommentBlock(inputModule.Type.Pos)
382 if translation, translated, err := getCommentTranslation(comment); err != nil {
383 return err
384 } else if translated {
385 w.WriteString(translation)
386 return nil
387 }
388
Colin Cross70a5f072015-06-29 17:44:56 -0700389 if ignoredModuleType[inputModule.Type.Name] {
390 return nil
391 }
392
Colin Crossb0931242015-06-29 14:18:27 -0700393 modules, err := w.mutateModule(newModule(inputModule))
394 if err != nil {
395 return err
396 }
Dan Willemsen49f50452015-06-24 14:56:00 -0700397
398 for _, module := range modules {
Colin Crossb0931242015-06-29 14:18:27 -0700399 err := w.parsePropsAndWriteModule(module)
400 if err != nil {
401 return err
402 }
Andres Moralesaf11df12015-04-30 12:14:34 -0700403 }
Colin Crossb0931242015-06-29 14:18:27 -0700404
405 return nil
Andres Moralesaf11df12015-04-30 12:14:34 -0700406}
407
408func (w *androidMkWriter) handleSubdirs(value bpparser.Value) {
Andres Morales8ae47de2015-05-11 12:26:07 -0700409 subdirs := make([]string, 0, len(value.ListValue))
410 for _, tok := range value.ListValue {
411 subdirs = append(subdirs, tok.StringValue)
Andres Moralesda8706f2015-04-29 12:46:49 -0700412 }
Ying Wang38284902015-06-02 18:44:59 -0700413 // The current makefile may be generated to outside the source tree (such as the out directory), with a different structure.
414 fmt.Fprintf(w, "# Uncomment the following line if you really want to include subdir Android.mks.\n")
415 fmt.Fprintf(w, "# include $(wildcard $(addsuffix $(LOCAL_PATH)/%s/, Android.mk))\n", strings.Join(subdirs, " "))
Andres Moralesda8706f2015-04-29 12:46:49 -0700416}
417
Colin Crossb0931242015-06-29 14:18:27 -0700418func (w *androidMkWriter) handleAssignment(assignment *bpparser.Assignment) error {
Colin Crossb1a66c02015-06-29 16:24:57 -0700419 comment := w.getCommentBlock(assignment.Name.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
Andres Moralesaf11df12015-04-30 12:14:34 -0700427 if "subdirs" == assignment.Name.Name {
428 w.handleSubdirs(assignment.OrigValue)
429 } else if assignment.OrigValue.Type == bpparser.Map {
430 // maps may be assigned in Soong, but can only be translated to .mk
431 // in the context of the module
432 w.mapScope[assignment.Name.Name] = assignment.OrigValue.MapValue
433 } else {
434 assigner := ":="
435 if assignment.Assigner != "=" {
436 assigner = assignment.Assigner
437 }
Colin Crossb0931242015-06-29 14:18:27 -0700438 val, err := valueToString(assignment.OrigValue)
439 if err != nil {
440 return err
441 }
442 fmt.Fprintf(w, "%s %s %s\n", assignment.Name.Name, assigner, val)
Andres Moralesda8706f2015-04-29 12:46:49 -0700443 }
Colin Crossb0931242015-06-29 14:18:27 -0700444
445 return nil
Andres Moralesda8706f2015-04-29 12:46:49 -0700446}
447
Andres Morales8ae47de2015-05-11 12:26:07 -0700448func (w *androidMkWriter) handleLocalPath() error {
Dan Willemsen360a39c2015-06-11 14:34:50 -0700449 if w.printedLocalPath {
450 return nil
451 }
452 w.printedLocalPath = true
453
Ying Wang38284902015-06-02 18:44:59 -0700454 localPath, err := filepath.Abs(w.path)
Andres Morales8ae47de2015-05-11 12:26:07 -0700455 if err != nil {
456 return err
457 }
458
Ying Wang38284902015-06-02 18:44:59 -0700459 top, err := getTopOfAndroidTree(localPath)
Andres Morales8ae47de2015-05-11 12:26:07 -0700460 if err != nil {
461 return err
462 }
463
Ying Wang38284902015-06-02 18:44:59 -0700464 rel, err := filepath.Rel(top, localPath)
Andres Morales8ae47de2015-05-11 12:26:07 -0700465 if err != nil {
466 return err
467 }
468
469 w.WriteString("LOCAL_PATH := " + rel + "\n")
Dan Willemsenc2666e62015-06-10 16:18:58 -0700470 w.WriteString("LOCAL_MODULE_MAKEFILE := $(lastword $(MAKEFILE_LIST))\n\n")
Andres Morales8ae47de2015-05-11 12:26:07 -0700471 return nil
472}
473
Colin Crossb1a66c02015-06-29 16:24:57 -0700474// Returns any block comment on the line preceding pos as a string
475func (w *androidMkWriter) getCommentBlock(pos scanner.Position) string {
476 var buf []byte
477
478 comments := w.blueprint.Comments
479 for i, c := range comments {
480 if c.EndLine() == pos.Line-1 {
481 line := pos.Line
482 for j := i; j >= 0; j-- {
483 c = comments[j]
484 if c.EndLine() == line-1 {
485 buf = append([]byte(c.Text()), buf...)
486 line = c.Pos.Line
487 } else {
488 break
489 }
490 }
491 }
492 }
493
494 return string(buf)
495}
496
497func getCommentTranslation(comment string) (string, bool, error) {
498 lines := strings.Split(comment, "\n")
499
500 if directive, i, err := getCommentDirective(lines); err != nil {
501 return "", false, err
502 } else if directive != "" {
503 switch directive {
504 case "ignore":
505 return "", true, nil
506 case "start":
507 return getCommentTranslationBlock(lines[i+1:])
508 case "end":
509 return "", false, fmt.Errorf("Unexpected Android.mk:end translation directive")
510 default:
511 return "", false, fmt.Errorf("Unknown Android.mk module translation directive %q", directive)
512 }
513 }
514
515 return "", false, nil
516}
517
518func getCommentTranslationBlock(lines []string) (string, bool, error) {
519 var buf []byte
520
521 for _, line := range lines {
522 if directive := getLineCommentDirective(line); directive != "" {
523 switch directive {
524 case "end":
525 return string(buf), true, nil
526 default:
527 return "", false, fmt.Errorf("Unexpected Android.mk translation directive %q inside start", directive)
528 }
529 } else {
530 buf = append(buf, line...)
531 buf = append(buf, '\n')
532 }
533 }
534
535 return "", false, fmt.Errorf("Missing Android.mk:end translation directive")
536}
537
538func getCommentDirective(lines []string) (directive string, n int, err error) {
539 for i, line := range lines {
540 if directive := getLineCommentDirective(line); directive != "" {
541 return strings.ToLower(directive), i, nil
542 }
543 }
544
545 return "", -1, nil
546}
547
548func getLineCommentDirective(line string) string {
549 line = strings.TrimSpace(line)
550 if strings.HasPrefix(line, "Android.mk:") {
551 line = strings.TrimPrefix(line, "Android.mk:")
552 line = strings.TrimSpace(line)
553 return line
554 }
555
556 return ""
557}
558
Colin Crossb0931242015-06-29 14:18:27 -0700559func (w *androidMkWriter) write(writer io.Writer) (err error) {
560 w.Writer = writer
Andres Moralesda8706f2015-04-29 12:46:49 -0700561
Colin Crossb0931242015-06-29 14:18:27 -0700562 if err = w.handleLocalPath(); err != nil {
Colin Cross26478b72015-06-29 13:46:00 -0700563 return err
564 }
565
566 for _, block := range w.blueprint.Defs {
Andres Moralesda8706f2015-04-29 12:46:49 -0700567 switch block := block.(type) {
568 case *bpparser.Module:
Colin Crossb0931242015-06-29 14:18:27 -0700569 err = w.handleModule(block)
Andres Moralesda8706f2015-04-29 12:46:49 -0700570 case *bpparser.Assignment:
Colin Crossb0931242015-06-29 14:18:27 -0700571 err = w.handleAssignment(block)
572 default:
573 return fmt.Errorf("Unhandled def %v", block)
574 }
575 if err != nil {
576 return err
Andres Moralesda8706f2015-04-29 12:46:49 -0700577 }
578 }
579
Ying Wang38284902015-06-02 18:44:59 -0700580 return nil
Andres Moralesda8706f2015-04-29 12:46:49 -0700581}
582
Colin Crossb0931242015-06-29 14:18:27 -0700583func translate(androidBp, androidMk string) error {
Ying Wang38284902015-06-02 18:44:59 -0700584 reader, err := os.Open(androidBp)
Andres Moralesda8706f2015-04-29 12:46:49 -0700585 if err != nil {
Colin Crossb0931242015-06-29 14:18:27 -0700586 return err
Andres Moralesda8706f2015-04-29 12:46:49 -0700587 }
588
589 scope := bpparser.NewScope(nil)
Ying Wang38284902015-06-02 18:44:59 -0700590 blueprint, errs := bpparser.Parse(androidBp, reader, scope)
Andres Moralesda8706f2015-04-29 12:46:49 -0700591 if len(errs) > 0 {
Colin Crossb0931242015-06-29 14:18:27 -0700592 return errs[0]
Andres Moralesda8706f2015-04-29 12:46:49 -0700593 }
594
595 writer := &androidMkWriter{
Andres Moralesaf11df12015-04-30 12:14:34 -0700596 blueprint: blueprint,
Ying Wang38284902015-06-02 18:44:59 -0700597 path: path.Dir(androidBp),
Andres Moralesaf11df12015-04-30 12:14:34 -0700598 mapScope: make(map[string][]*bpparser.Property),
Andres Moralesda8706f2015-04-29 12:46:49 -0700599 }
600
Colin Crossb0931242015-06-29 14:18:27 -0700601 buf := &bytes.Buffer{}
602
603 err = writer.write(buf)
Ying Wang38284902015-06-02 18:44:59 -0700604 if err != nil {
Colin Crossb0931242015-06-29 14:18:27 -0700605 os.Remove(androidMk)
606 return err
607 }
608
609 f, err := os.Create(androidMk)
610 if err != nil {
611 return err
612 }
613 defer f.Close()
614
615 _, err = f.Write(buf.Bytes())
616
617 return err
618}
619
620func main() {
621 if len(os.Args) < 3 {
622 fmt.Fprintln(os.Stderr, "Expected input and output filename arguments")
623 os.Exit(1)
624 }
625
626 androidBp := os.Args[1]
627 androidMk := os.Args[2]
628
629 err := translate(androidBp, androidMk)
630
631 if err != nil {
632 fmt.Fprintf(os.Stderr, "Error translating %s: %s\n", androidBp, err.Error())
Ying Wang38284902015-06-02 18:44:59 -0700633 os.Exit(1)
634 }
Andres Moralesda8706f2015-04-29 12:46:49 -0700635}