1// Copyright 2017 Google Inc. All rights reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package main
16
17import (
18	mkparser "android/soong/androidmk/parser"
19	"fmt"
20	"sort"
21	"strings"
22
23	bpparser "github.com/google/blueprint/parser"
24)
25
26const (
27	clear_vars      = "__android_mk_clear_vars"
28	include_ignored = "__android_mk_include_ignored"
29)
30
31type bpVariable struct {
32	name         string
33	variableType bpparser.Type
34}
35
36type variableAssignmentContext struct {
37	file    *bpFile
38	prefix  string
39	mkvalue *mkparser.MakeString
40	append  bool
41}
42
43var rewriteProperties = map[string](func(variableAssignmentContext) error){
44	// custom functions
45	"LOCAL_AIDL_INCLUDES":         localAidlIncludes,
46	"LOCAL_C_INCLUDES":            localIncludeDirs,
47	"LOCAL_EXPORT_C_INCLUDE_DIRS": exportIncludeDirs,
48	"LOCAL_LDFLAGS":               ldflags,
49	"LOCAL_MODULE_CLASS":          prebuiltClass,
50	"LOCAL_MODULE_STEM":           stem,
51	"LOCAL_MODULE_HOST_OS":        hostOs,
52	"LOCAL_SANITIZE":              sanitize(""),
53	"LOCAL_SANITIZE_DIAG":         sanitize("diag."),
54	"LOCAL_CFLAGS":                cflags,
55	"LOCAL_UNINSTALLABLE_MODULE":  invert("installable"),
56	"LOCAL_PROGUARD_ENABLED":      proguardEnabled,
57
58	// composite functions
59	"LOCAL_MODULE_TAGS": includeVariableIf(bpVariable{"tags", bpparser.ListType}, not(valueDumpEquals("optional"))),
60
61	// skip functions
62	"LOCAL_ADDITIONAL_DEPENDENCIES": skip, // TODO: check for only .mk files?
63	"LOCAL_CPP_EXTENSION":           skip,
64	"LOCAL_MODULE_SUFFIX":           skip, // TODO
65	"LOCAL_PATH":                    skip, // Nothing to do, except maybe avoid the "./" in paths?
66	"LOCAL_PRELINK_MODULE":          skip, // Already phased out
67	"LOCAL_BUILT_MODULE_STEM":       skip,
68	"LOCAL_USE_AAPT2":               skip, // Always enabled in Soong
69	"LOCAL_JAR_EXCLUDE_FILES":       skip, // Soong never excludes files from jars
70}
71
72// adds a group of properties all having the same type
73func addStandardProperties(propertyType bpparser.Type, properties map[string]string) {
74	for key, val := range properties {
75		rewriteProperties[key] = includeVariable(bpVariable{val, propertyType})
76	}
77}
78
79func init() {
80	addStandardProperties(bpparser.StringType,
81		map[string]string{
82			"LOCAL_MODULE":                  "name",
83			"LOCAL_CXX_STL":                 "stl",
84			"LOCAL_STRIP_MODULE":            "strip",
85			"LOCAL_MULTILIB":                "compile_multilib",
86			"LOCAL_ARM_MODE_HACK":           "instruction_set",
87			"LOCAL_SDK_VERSION":             "sdk_version",
88			"LOCAL_NDK_STL_VARIANT":         "stl",
89			"LOCAL_JAR_MANIFEST":            "manifest",
90			"LOCAL_JARJAR_RULES":            "jarjar_rules",
91			"LOCAL_CERTIFICATE":             "certificate",
92			"LOCAL_PACKAGE_NAME":            "name",
93			"LOCAL_MODULE_RELATIVE_PATH":    "relative_install_path",
94			"LOCAL_PROTOC_OPTIMIZE_TYPE":    "proto.type",
95			"LOCAL_MODULE_OWNER":            "owner",
96			"LOCAL_RENDERSCRIPT_TARGET_API": "renderscript.target_api",
97			"LOCAL_NOTICE_FILE":             "notice",
98			"LOCAL_JAVA_LANGUAGE_VERSION":   "java_version",
99			"LOCAL_INSTRUMENTATION_FOR":     "instrumentation_for",
100			"LOCAL_MANIFEST_FILE":           "manifest",
101
102			"LOCAL_DEX_PREOPT_PROFILE_CLASS_LISTING": "dex_preopt.profile",
103		})
104	addStandardProperties(bpparser.ListType,
105		map[string]string{
106			"LOCAL_SRC_FILES":                     "srcs",
107			"LOCAL_SRC_FILES_EXCLUDE":             "exclude_srcs",
108			"LOCAL_HEADER_LIBRARIES":              "header_libs",
109			"LOCAL_SHARED_LIBRARIES":              "shared_libs",
110			"LOCAL_STATIC_LIBRARIES":              "static_libs",
111			"LOCAL_WHOLE_STATIC_LIBRARIES":        "whole_static_libs",
112			"LOCAL_SYSTEM_SHARED_LIBRARIES":       "system_shared_libs",
113			"LOCAL_ASFLAGS":                       "asflags",
114			"LOCAL_CLANG_ASFLAGS":                 "clang_asflags",
115			"LOCAL_CONLYFLAGS":                    "conlyflags",
116			"LOCAL_CPPFLAGS":                      "cppflags",
117			"LOCAL_REQUIRED_MODULES":              "required",
118			"LOCAL_OVERRIDES_MODULES":             "overrides",
119			"LOCAL_LDLIBS":                        "host_ldlibs",
120			"LOCAL_CLANG_CFLAGS":                  "clang_cflags",
121			"LOCAL_YACCFLAGS":                     "yaccflags",
122			"LOCAL_SANITIZE_RECOVER":              "sanitize.recover",
123			"LOCAL_LOGTAGS_FILES":                 "logtags",
124			"LOCAL_EXPORT_HEADER_LIBRARY_HEADERS": "export_header_lib_headers",
125			"LOCAL_EXPORT_SHARED_LIBRARY_HEADERS": "export_shared_lib_headers",
126			"LOCAL_EXPORT_STATIC_LIBRARY_HEADERS": "export_static_lib_headers",
127			"LOCAL_INIT_RC":                       "init_rc",
128			"LOCAL_TIDY_FLAGS":                    "tidy_flags",
129			// TODO: This is comma-separated, not space-separated
130			"LOCAL_TIDY_CHECKS":           "tidy_checks",
131			"LOCAL_RENDERSCRIPT_INCLUDES": "renderscript.include_dirs",
132			"LOCAL_RENDERSCRIPT_FLAGS":    "renderscript.flags",
133
134			"LOCAL_JAVA_RESOURCE_DIRS":    "java_resource_dirs",
135			"LOCAL_RESOURCE_DIR":          "resource_dirs",
136			"LOCAL_JAVACFLAGS":            "javacflags",
137			"LOCAL_ERROR_PRONE_FLAGS":     "errorprone.javacflags",
138			"LOCAL_DX_FLAGS":              "dxflags",
139			"LOCAL_JAVA_LIBRARIES":        "libs",
140			"LOCAL_STATIC_JAVA_LIBRARIES": "static_libs",
141			"LOCAL_AAPT_FLAGS":            "aaptflags",
142			"LOCAL_PACKAGE_SPLITS":        "package_splits",
143			"LOCAL_COMPATIBILITY_SUITE":   "test_suites",
144
145			"LOCAL_ANNOTATION_PROCESSORS":        "annotation_processors",
146			"LOCAL_ANNOTATION_PROCESSOR_CLASSES": "annotation_processor_classes",
147
148			"LOCAL_PROGUARD_FLAGS":      "optimize.proguard_flags",
149			"LOCAL_PROGUARD_FLAG_FILES": "optimize.proguard_flag_files",
150
151			// These will be rewritten to libs/static_libs by bpfix, after their presence is used to convert
152			// java_library_static to android_library.
153			"LOCAL_SHARED_ANDROID_LIBRARIES": "android_libs",
154			"LOCAL_STATIC_ANDROID_LIBRARIES": "android_static_libs",
155		})
156
157	addStandardProperties(bpparser.BoolType,
158		map[string]string{
159			// Bool properties
160			"LOCAL_IS_HOST_MODULE":           "host",
161			"LOCAL_CLANG":                    "clang",
162			"LOCAL_FORCE_STATIC_EXECUTABLE":  "static_executable",
163			"LOCAL_NATIVE_COVERAGE":          "native_coverage",
164			"LOCAL_NO_CRT":                   "nocrt",
165			"LOCAL_ALLOW_UNDEFINED_SYMBOLS":  "allow_undefined_symbols",
166			"LOCAL_RTTI_FLAG":                "rtti",
167			"LOCAL_NO_STANDARD_LIBRARIES":    "no_standard_libs",
168			"LOCAL_PACK_MODULE_RELOCATIONS":  "pack_relocations",
169			"LOCAL_TIDY":                     "tidy",
170			"LOCAL_PROPRIETARY_MODULE":       "proprietary",
171			"LOCAL_VENDOR_MODULE":            "vendor",
172			"LOCAL_ODM_MODULE":               "device_specific",
173			"LOCAL_PRODUCT_MODULE":           "product_specific",
174			"LOCAL_EXPORT_PACKAGE_RESOURCES": "export_package_resources",
175			"LOCAL_PRIVILEGED_MODULE":        "privileged",
176
177			"LOCAL_DEX_PREOPT":                  "dex_preopt.enabled",
178			"LOCAL_DEX_PREOPT_APP_IMAGE":        "dex_preopt.app_image",
179			"LOCAL_DEX_PREOPT_GENERATE_PROFILE": "dex_preopt.profile_guided",
180		})
181}
182
183type listSplitFunc func(bpparser.Expression) (string, bpparser.Expression, error)
184
185func emptyList(value bpparser.Expression) bool {
186	if list, ok := value.(*bpparser.List); ok {
187		return len(list.Values) == 0
188	}
189	return false
190}
191
192func splitBpList(val bpparser.Expression, keyFunc listSplitFunc) (lists map[string]bpparser.Expression, err error) {
193	lists = make(map[string]bpparser.Expression)
194
195	switch val := val.(type) {
196	case *bpparser.Operator:
197		listsA, err := splitBpList(val.Args[0], keyFunc)
198		if err != nil {
199			return nil, err
200		}
201
202		listsB, err := splitBpList(val.Args[1], keyFunc)
203		if err != nil {
204			return nil, err
205		}
206
207		for k, v := range listsA {
208			if !emptyList(v) {
209				lists[k] = v
210			}
211		}
212
213		for k, vB := range listsB {
214			if emptyList(vB) {
215				continue
216			}
217
218			if vA, ok := lists[k]; ok {
219				expression := val.Copy().(*bpparser.Operator)
220				expression.Args = [2]bpparser.Expression{vA, vB}
221				lists[k] = expression
222			} else {
223				lists[k] = vB
224			}
225		}
226	case *bpparser.Variable:
227		key, value, err := keyFunc(val)
228		if err != nil {
229			return nil, err
230		}
231		if value.Type() == bpparser.ListType {
232			lists[key] = value
233		} else {
234			lists[key] = &bpparser.List{
235				Values: []bpparser.Expression{value},
236			}
237		}
238	case *bpparser.List:
239		for _, v := range val.Values {
240			key, value, err := keyFunc(v)
241			if err != nil {
242				return nil, err
243			}
244			l := lists[key]
245			if l == nil {
246				l = &bpparser.List{}
247			}
248			l.(*bpparser.List).Values = append(l.(*bpparser.List).Values, value)
249			lists[key] = l
250		}
251	default:
252		panic(fmt.Errorf("unexpected type %t", val))
253	}
254
255	return lists, nil
256}
257
258// classifyLocalOrGlobalPath tells whether a file path should be interpreted relative to the current module (local)
259// or relative to the root of the source checkout (global)
260func classifyLocalOrGlobalPath(value bpparser.Expression) (string, bpparser.Expression, error) {
261	switch v := value.(type) {
262	case *bpparser.Variable:
263		if v.Name == "LOCAL_PATH" {
264			return "local", &bpparser.String{
265				Value: ".",
266			}, nil
267		} else {
268			// TODO: Should we split variables?
269			return "global", value, nil
270		}
271	case *bpparser.Operator:
272		if v.Type() != bpparser.StringType {
273			return "", nil, fmt.Errorf("classifyLocalOrGlobalPath expected a string, got %s", v.Type())
274		}
275
276		if v.Operator != '+' {
277			return "global", value, nil
278		}
279
280		firstOperand := v.Args[0]
281		secondOperand := v.Args[1]
282		if firstOperand.Type() != bpparser.StringType {
283			return "global", value, nil
284		}
285
286		if _, ok := firstOperand.(*bpparser.Operator); ok {
287			return "global", value, nil
288		}
289
290		if variable, ok := firstOperand.(*bpparser.Variable); !ok || variable.Name != "LOCAL_PATH" {
291			return "global", value, nil
292		}
293
294		local := secondOperand
295		if s, ok := secondOperand.(*bpparser.String); ok {
296			if strings.HasPrefix(s.Value, "/") {
297				s.Value = s.Value[1:]
298			}
299		}
300		return "local", local, nil
301	case *bpparser.String:
302		return "global", value, nil
303	default:
304		return "", nil, fmt.Errorf("classifyLocalOrGlobalPath expected a string, got %s", v.Type())
305
306	}
307}
308
309func sortedMapKeys(inputMap map[string]string) (sortedKeys []string) {
310	keys := make([]string, 0, len(inputMap))
311	for key := range inputMap {
312		keys = append(keys, key)
313	}
314	sort.Strings(keys)
315	return keys
316}
317
318// splitAndAssign splits a Make list into components and then
319// creates the corresponding variable assignments.
320func splitAndAssign(ctx variableAssignmentContext, splitFunc listSplitFunc, namesByClassification map[string]string) error {
321	val, err := makeVariableToBlueprint(ctx.file, ctx.mkvalue, bpparser.ListType)
322	if err != nil {
323		return err
324	}
325
326	lists, err := splitBpList(val, splitFunc)
327	if err != nil {
328		return err
329	}
330
331	for _, nameClassification := range sortedMapKeys(namesByClassification) {
332		name := namesByClassification[nameClassification]
333		if component, ok := lists[nameClassification]; ok && !emptyList(component) {
334			err = setVariable(ctx.file, ctx.append, ctx.prefix, name, component, true)
335			if err != nil {
336				return err
337			}
338		}
339	}
340	return nil
341}
342
343func localIncludeDirs(ctx variableAssignmentContext) error {
344	return splitAndAssign(ctx, classifyLocalOrGlobalPath, map[string]string{"global": "include_dirs", "local": "local_include_dirs"})
345}
346
347func exportIncludeDirs(ctx variableAssignmentContext) error {
348	// Add any paths that could not be converted to local relative paths to export_include_dirs
349	// anyways, they will cause an error if they don't exist and can be fixed manually.
350	return splitAndAssign(ctx, classifyLocalOrGlobalPath, map[string]string{"global": "export_include_dirs", "local": "export_include_dirs"})
351}
352
353func localAidlIncludes(ctx variableAssignmentContext) error {
354	return splitAndAssign(ctx, classifyLocalOrGlobalPath, map[string]string{"global": "aidl.include_dirs", "local": "aidl.local_include_dirs"})
355}
356
357func stem(ctx variableAssignmentContext) error {
358	val, err := makeVariableToBlueprint(ctx.file, ctx.mkvalue, bpparser.StringType)
359	if err != nil {
360		return err
361	}
362	varName := "stem"
363
364	if exp, ok := val.(*bpparser.Operator); ok && exp.Operator == '+' {
365		if variable, ok := exp.Args[0].(*bpparser.Variable); ok && variable.Name == "LOCAL_MODULE" {
366			varName = "suffix"
367			val = exp.Args[1]
368		}
369	}
370
371	return setVariable(ctx.file, ctx.append, ctx.prefix, varName, val, true)
372}
373
374func hostOs(ctx variableAssignmentContext) error {
375	val, err := makeVariableToBlueprint(ctx.file, ctx.mkvalue, bpparser.ListType)
376	if err != nil {
377		return err
378	}
379
380	inList := func(s string) bool {
381		for _, v := range val.(*bpparser.List).Values {
382			if v.(*bpparser.String).Value == s {
383				return true
384			}
385		}
386		return false
387	}
388
389	falseValue := &bpparser.Bool{
390		Value: false,
391	}
392
393	trueValue := &bpparser.Bool{
394		Value: true,
395	}
396
397	if inList("windows") {
398		err = setVariable(ctx.file, ctx.append, "target.windows", "enabled", trueValue, true)
399	}
400
401	if !inList("linux") && err == nil {
402		err = setVariable(ctx.file, ctx.append, "target.linux_glibc", "enabled", falseValue, true)
403	}
404
405	if !inList("darwin") && err == nil {
406		err = setVariable(ctx.file, ctx.append, "target.darwin", "enabled", falseValue, true)
407	}
408
409	return err
410}
411
412func sanitize(sub string) func(ctx variableAssignmentContext) error {
413	return func(ctx variableAssignmentContext) error {
414		val, err := makeVariableToBlueprint(ctx.file, ctx.mkvalue, bpparser.ListType)
415		if err != nil {
416			return err
417		}
418
419		if _, ok := val.(*bpparser.List); !ok {
420			return fmt.Errorf("unsupported sanitize expression")
421		}
422
423		misc := &bpparser.List{}
424
425		for _, v := range val.(*bpparser.List).Values {
426			switch v := v.(type) {
427			case *bpparser.Variable, *bpparser.Operator:
428				ctx.file.errorf(ctx.mkvalue, "unsupported sanitize expression")
429			case *bpparser.String:
430				switch v.Value {
431				case "never", "address", "coverage", "thread", "undefined", "cfi":
432					bpTrue := &bpparser.Bool{
433						Value: true,
434					}
435					err = setVariable(ctx.file, false, ctx.prefix, "sanitize."+sub+v.Value, bpTrue, true)
436					if err != nil {
437						return err
438					}
439				default:
440					misc.Values = append(misc.Values, v)
441				}
442			default:
443				return fmt.Errorf("sanitize expected a string, got %s", v.Type())
444			}
445		}
446
447		if len(misc.Values) > 0 {
448			err = setVariable(ctx.file, false, ctx.prefix, "sanitize."+sub+"misc_undefined", misc, true)
449			if err != nil {
450				return err
451			}
452		}
453
454		return err
455	}
456}
457
458func prebuiltClass(ctx variableAssignmentContext) error {
459	class := ctx.mkvalue.Value(ctx.file.scope)
460	if v, ok := prebuiltTypes[class]; ok {
461		ctx.file.scope.Set("BUILD_PREBUILT", v)
462	} else {
463		// reset to default
464		ctx.file.scope.Set("BUILD_PREBUILT", "prebuilt")
465	}
466	return nil
467}
468
469func ldflags(ctx variableAssignmentContext) error {
470	val, err := makeVariableToBlueprint(ctx.file, ctx.mkvalue, bpparser.ListType)
471	if err != nil {
472		return err
473	}
474
475	lists, err := splitBpList(val, func(value bpparser.Expression) (string, bpparser.Expression, error) {
476		// Anything other than "-Wl,--version_script," + LOCAL_PATH + "<path>" matches ldflags
477		exp1, ok := value.(*bpparser.Operator)
478		if !ok {
479			return "ldflags", value, nil
480		}
481
482		exp2, ok := exp1.Args[0].(*bpparser.Operator)
483		if !ok {
484			return "ldflags", value, nil
485		}
486
487		if s, ok := exp2.Args[0].(*bpparser.String); !ok || s.Value != "-Wl,--version-script," {
488			return "ldflags", value, nil
489		}
490
491		if v, ok := exp2.Args[1].(*bpparser.Variable); !ok || v.Name != "LOCAL_PATH" {
492			ctx.file.errorf(ctx.mkvalue, "Unrecognized version-script")
493			return "ldflags", value, nil
494		}
495
496		s, ok := exp1.Args[1].(*bpparser.String)
497		if !ok {
498			ctx.file.errorf(ctx.mkvalue, "Unrecognized version-script")
499			return "ldflags", value, nil
500		}
501
502		s.Value = strings.TrimPrefix(s.Value, "/")
503
504		return "version", s, nil
505	})
506	if err != nil {
507		return err
508	}
509
510	if ldflags, ok := lists["ldflags"]; ok && !emptyList(ldflags) {
511		err = setVariable(ctx.file, ctx.append, ctx.prefix, "ldflags", ldflags, true)
512		if err != nil {
513			return err
514		}
515	}
516
517	if version_script, ok := lists["version"]; ok && !emptyList(version_script) {
518		if len(version_script.(*bpparser.List).Values) > 1 {
519			ctx.file.errorf(ctx.mkvalue, "multiple version scripts found?")
520		}
521		err = setVariable(ctx.file, false, ctx.prefix, "version_script", version_script.(*bpparser.List).Values[0], true)
522		if err != nil {
523			return err
524		}
525	}
526
527	return nil
528}
529
530func cflags(ctx variableAssignmentContext) error {
531	// The Soong replacement for CFLAGS doesn't need the same extra escaped quotes that were present in Make
532	ctx.mkvalue = ctx.mkvalue.Clone()
533	ctx.mkvalue.ReplaceLiteral(`\"`, `"`)
534	return includeVariableNow(bpVariable{"cflags", bpparser.ListType}, ctx)
535}
536
537func proguardEnabled(ctx variableAssignmentContext) error {
538	val, err := makeVariableToBlueprint(ctx.file, ctx.mkvalue, bpparser.ListType)
539	if err != nil {
540		return err
541	}
542
543	list, ok := val.(*bpparser.List)
544	if !ok {
545		return fmt.Errorf("unsupported proguard expression")
546	}
547
548	set := func(prop string, value bool) {
549		bpValue := &bpparser.Bool{
550			Value: value,
551		}
552		setVariable(ctx.file, false, ctx.prefix, prop, bpValue, true)
553	}
554
555	enable := false
556
557	for _, v := range list.Values {
558		s, ok := v.(*bpparser.String)
559		if !ok {
560			return fmt.Errorf("unsupported proguard expression")
561		}
562
563		switch s.Value {
564		case "disabled":
565			set("optimize.enabled", false)
566		case "obfuscation":
567			enable = true
568			set("optimize.obfuscate", true)
569		case "optimization":
570			enable = true
571			set("optimize.optimize", true)
572		case "full":
573			enable = true
574		case "custom":
575			set("optimize.no_aapt_flags", true)
576			enable = true
577		default:
578			return fmt.Errorf("unsupported proguard value %q", s)
579		}
580	}
581
582	if enable {
583		// This is only necessary for libraries which default to false, but we can't
584		// tell the difference between a library and an app here.
585		set("optimize.enabled", true)
586	}
587
588	return nil
589}
590
591func invert(name string) func(ctx variableAssignmentContext) error {
592	return func(ctx variableAssignmentContext) error {
593		val, err := makeVariableToBlueprint(ctx.file, ctx.mkvalue, bpparser.BoolType)
594		if err != nil {
595			return err
596		}
597
598		val.(*bpparser.Bool).Value = !val.(*bpparser.Bool).Value
599
600		return setVariable(ctx.file, ctx.append, ctx.prefix, name, val, true)
601	}
602}
603
604// given a conditional, returns a function that will insert a variable assignment or not, based on the conditional
605func includeVariableIf(bpVar bpVariable, conditional func(ctx variableAssignmentContext) bool) func(ctx variableAssignmentContext) error {
606	return func(ctx variableAssignmentContext) error {
607		var err error
608		if conditional(ctx) {
609			err = includeVariableNow(bpVar, ctx)
610		}
611		return err
612	}
613}
614
615// given a variable, returns a function that will always insert a variable assignment
616func includeVariable(bpVar bpVariable) func(ctx variableAssignmentContext) error {
617	return includeVariableIf(bpVar, always)
618}
619
620func includeVariableNow(bpVar bpVariable, ctx variableAssignmentContext) error {
621	var val bpparser.Expression
622	var err error
623	val, err = makeVariableToBlueprint(ctx.file, ctx.mkvalue, bpVar.variableType)
624	if err == nil {
625		err = setVariable(ctx.file, ctx.append, ctx.prefix, bpVar.name, val, true)
626	}
627	return err
628}
629
630// given a function that returns a bool, returns a function that returns the opposite
631func not(conditional func(ctx variableAssignmentContext) bool) func(ctx variableAssignmentContext) bool {
632	return func(ctx variableAssignmentContext) bool {
633		return !conditional(ctx)
634	}
635}
636
637// returns a function that tells whether mkvalue.Dump equals the given query string
638func valueDumpEquals(textToMatch string) func(ctx variableAssignmentContext) bool {
639	return func(ctx variableAssignmentContext) bool {
640		return (ctx.mkvalue.Dump() == textToMatch)
641	}
642}
643
644func always(ctx variableAssignmentContext) bool {
645	return true
646}
647
648func skip(ctx variableAssignmentContext) error {
649	return nil
650}
651
652// Shorter suffixes of other suffixes must be at the end of the list
653var propertyPrefixes = []struct{ mk, bp string }{
654	{"arm", "arch.arm"},
655	{"arm64", "arch.arm64"},
656	{"mips", "arch.mips"},
657	{"mips64", "arch.mips64"},
658	{"x86", "arch.x86"},
659	{"x86_64", "arch.x86_64"},
660	{"32", "multilib.lib32"},
661	// 64 must be after x86_64
662	{"64", "multilib.lib64"},
663	{"darwin", "target.darwin"},
664	{"linux", "target.linux_glibc"},
665	{"windows", "target.windows"},
666}
667
668var conditionalTranslations = map[string]map[bool]string{
669	"($(HOST_OS),darwin)": {
670		true:  "target.darwin",
671		false: "target.not_darwin"},
672	"($(HOST_OS), darwin)": {
673		true:  "target.darwin",
674		false: "target.not_darwin"},
675	"($(HOST_OS),windows)": {
676		true:  "target.windows",
677		false: "target.not_windows"},
678	"($(HOST_OS), windows)": {
679		true:  "target.windows",
680		false: "target.not_windows"},
681	"($(HOST_OS),linux)": {
682		true:  "target.linux_glibc",
683		false: "target.not_linux_glibc"},
684	"($(HOST_OS), linux)": {
685		true:  "target.linux_glibc",
686		false: "target.not_linux_glibc"},
687	"($(BUILD_OS),darwin)": {
688		true:  "target.darwin",
689		false: "target.not_darwin"},
690	"($(BUILD_OS), darwin)": {
691		true:  "target.darwin",
692		false: "target.not_darwin"},
693	"($(BUILD_OS),linux)": {
694		true:  "target.linux_glibc",
695		false: "target.not_linux_glibc"},
696	"($(BUILD_OS), linux)": {
697		true:  "target.linux_glibc",
698		false: "target.not_linux_glibc"},
699	"(,$(TARGET_BUILD_APPS))": {
700		false: "product_variables.unbundled_build"},
701	"($(TARGET_BUILD_APPS),)": {
702		false: "product_variables.unbundled_build"},
703	"($(TARGET_BUILD_PDK),true)": {
704		true: "product_variables.pdk"},
705	"($(TARGET_BUILD_PDK), true)": {
706		true: "product_variables.pdk"},
707}
708
709func mydir(args []string) string {
710	return "."
711}
712
713func allFilesUnder(wildcard string) func(args []string) string {
714	return func(args []string) string {
715		dir := ""
716		if len(args) > 0 {
717			dir = strings.TrimSpace(args[0])
718		}
719
720		return fmt.Sprintf("%s/**/"+wildcard, dir)
721	}
722}
723
724func allSubdirJavaFiles(args []string) string {
725	return "**/*.java"
726}
727
728func includeIgnored(args []string) string {
729	return include_ignored
730}
731
732var moduleTypes = map[string]string{
733	"BUILD_SHARED_LIBRARY":        "cc_library_shared",
734	"BUILD_STATIC_LIBRARY":        "cc_library_static",
735	"BUILD_HOST_SHARED_LIBRARY":   "cc_library_host_shared",
736	"BUILD_HOST_STATIC_LIBRARY":   "cc_library_host_static",
737	"BUILD_HEADER_LIBRARY":        "cc_library_headers",
738	"BUILD_EXECUTABLE":            "cc_binary",
739	"BUILD_HOST_EXECUTABLE":       "cc_binary_host",
740	"BUILD_NATIVE_TEST":           "cc_test",
741	"BUILD_HOST_NATIVE_TEST":      "cc_test_host",
742	"BUILD_NATIVE_BENCHMARK":      "cc_benchmark",
743	"BUILD_HOST_NATIVE_BENCHMARK": "cc_benchmark_host",
744
745	"BUILD_JAVA_LIBRARY":             "java_library",
746	"BUILD_STATIC_JAVA_LIBRARY":      "java_library_static",
747	"BUILD_HOST_JAVA_LIBRARY":        "java_library_host",
748	"BUILD_HOST_DALVIK_JAVA_LIBRARY": "java_library_host_dalvik",
749	"BUILD_PACKAGE":                  "android_app",
750}
751
752var prebuiltTypes = map[string]string{
753	"SHARED_LIBRARIES": "cc_prebuilt_library_shared",
754	"STATIC_LIBRARIES": "cc_prebuilt_library_static",
755	"EXECUTABLES":      "cc_prebuilt_binary",
756	"JAVA_LIBRARIES":   "java_import",
757}
758
759var soongModuleTypes = map[string]bool{}
760
761func androidScope() mkparser.Scope {
762	globalScope := mkparser.NewScope(nil)
763	globalScope.Set("CLEAR_VARS", clear_vars)
764	globalScope.SetFunc("my-dir", mydir)
765	globalScope.SetFunc("all-java-files-under", allFilesUnder("*.java"))
766	globalScope.SetFunc("all-proto-files-under", allFilesUnder("*.proto"))
767	globalScope.SetFunc("all-aidl-files-under", allFilesUnder("*.aidl"))
768	globalScope.SetFunc("all-Iaidl-files-under", allFilesUnder("I*.aidl"))
769	globalScope.SetFunc("all-logtags-files-under", allFilesUnder("*.logtags"))
770	globalScope.SetFunc("all-subdir-java-files", allSubdirJavaFiles)
771	globalScope.SetFunc("all-makefiles-under", includeIgnored)
772	globalScope.SetFunc("first-makefiles-under", includeIgnored)
773	globalScope.SetFunc("all-named-subdir-makefiles", includeIgnored)
774	globalScope.SetFunc("all-subdir-makefiles", includeIgnored)
775
776	for k, v := range moduleTypes {
777		globalScope.Set(k, v)
778		soongModuleTypes[v] = true
779	}
780	for _, v := range prebuiltTypes {
781		soongModuleTypes[v] = true
782	}
783
784	return globalScope
785}
786