| package main |
| |
| import ( |
| mkparser "android/soong/androidmk/parser" |
| "fmt" |
| "strings" |
| |
| bpparser "github.com/google/blueprint/parser" |
| ) |
| |
| const ( |
| clear_vars = "__android_mk_clear_vars" |
| ) |
| |
| var standardProperties = map[string]struct { |
| string |
| bpparser.ValueType |
| }{ |
| // String properties |
| "LOCAL_MODULE": {"name", bpparser.String}, |
| "LOCAL_MODULE_CLASS": {"class", bpparser.String}, |
| "LOCAL_CXX_STL": {"stl", bpparser.String}, |
| "LOCAL_STRIP_MODULE": {"strip", bpparser.String}, |
| "LOCAL_MULTILIB": {"compile_multilib", bpparser.String}, |
| "LOCAL_ARM_MODE_HACK": {"instruction_set", bpparser.String}, |
| "LOCAL_SDK_VERSION": {"sdk_version", bpparser.String}, |
| "LOCAL_NDK_STL_VARIANT": {"stl", bpparser.String}, |
| "LOCAL_JAR_MANIFEST": {"manifest", bpparser.String}, |
| "LOCAL_JARJAR_RULES": {"jarjar_rules", bpparser.String}, |
| "LOCAL_CERTIFICATE": {"certificate", bpparser.String}, |
| "LOCAL_PACKAGE_NAME": {"name", bpparser.String}, |
| "LOCAL_MODULE_RELATIVE_PATH": {"relative_install_path", bpparser.String}, |
| |
| // List properties |
| "LOCAL_SRC_FILES": {"srcs", bpparser.List}, |
| "LOCAL_SHARED_LIBRARIES": {"shared_libs", bpparser.List}, |
| "LOCAL_STATIC_LIBRARIES": {"static_libs", bpparser.List}, |
| "LOCAL_WHOLE_STATIC_LIBRARIES": {"whole_static_libs", bpparser.List}, |
| "LOCAL_SYSTEM_SHARED_LIBRARIES": {"system_shared_libs", bpparser.List}, |
| "LOCAL_ASFLAGS": {"asflags", bpparser.List}, |
| "LOCAL_CLANG_ASFLAGS": {"clang_asflags", bpparser.List}, |
| "LOCAL_CFLAGS": {"cflags", bpparser.List}, |
| "LOCAL_CONLYFLAGS": {"conlyflags", bpparser.List}, |
| "LOCAL_CPPFLAGS": {"cppflags", bpparser.List}, |
| "LOCAL_LDFLAGS": {"ldflags", bpparser.List}, |
| "LOCAL_REQUIRED_MODULES": {"required", bpparser.List}, |
| "LOCAL_MODULE_TAGS": {"tags", bpparser.List}, |
| "LOCAL_LDLIBS": {"host_ldlibs", bpparser.List}, |
| "LOCAL_CLANG_CFLAGS": {"clang_cflags", bpparser.List}, |
| "LOCAL_YACCFLAGS": {"yaccflags", bpparser.List}, |
| "LOCAL_SANITIZE": {"sanitize", bpparser.List}, |
| "LOCAL_SANITIZE_RECOVER": {"sanitize_recover", bpparser.List}, |
| |
| "LOCAL_JAVA_RESOURCE_DIRS": {"java_resource_dirs", bpparser.List}, |
| "LOCAL_JAVACFLAGS": {"javacflags", bpparser.List}, |
| "LOCAL_DX_FLAGS": {"dxflags", bpparser.List}, |
| "LOCAL_JAVA_LIBRARIES": {"java_libs", bpparser.List}, |
| "LOCAL_STATIC_JAVA_LIBRARIES": {"java_static_libs", bpparser.List}, |
| "LOCAL_AIDL_INCLUDES": {"aidl_includes", bpparser.List}, |
| "LOCAL_AAPT_FLAGS": {"aaptflags", bpparser.List}, |
| "LOCAL_PACKAGE_SPLITS": {"package_splits", bpparser.List}, |
| |
| // Bool properties |
| "LOCAL_IS_HOST_MODULE": {"host", bpparser.Bool}, |
| "LOCAL_CLANG": {"clang", bpparser.Bool}, |
| "LOCAL_FORCE_STATIC_EXECUTABLE": {"static", bpparser.Bool}, |
| "LOCAL_NATIVE_COVERAGE": {"native_coverage", bpparser.Bool}, |
| "LOCAL_NO_CRT": {"nocrt", bpparser.Bool}, |
| "LOCAL_ALLOW_UNDEFINED_SYMBOLS": {"allow_undefined_symbols", bpparser.Bool}, |
| "LOCAL_RTTI_FLAG": {"rtti", bpparser.Bool}, |
| |
| "LOCAL_NO_STANDARD_LIBRARIES": {"no_standard_libraries", bpparser.Bool}, |
| |
| "LOCAL_EXPORT_PACKAGE_RESOURCES": {"export_package_resources", bpparser.Bool}, |
| } |
| |
| var rewriteProperties = map[string]struct { |
| f func(file *bpFile, prefix string, value *mkparser.MakeString, append bool) error |
| }{ |
| "LOCAL_C_INCLUDES": {localIncludeDirs}, |
| "LOCAL_EXPORT_C_INCLUDE_DIRS": {exportIncludeDirs}, |
| "LOCAL_MODULE_STEM": {stem}, |
| "LOCAL_MODULE_HOST_OS": {hostOs}, |
| } |
| |
| func localAbsPath(value bpparser.Value) (*bpparser.Value, error) { |
| if value.Type != bpparser.String { |
| return nil, fmt.Errorf("isLocalAbsPath expected a string, got %d", value.Type) |
| } |
| |
| if value.Expression == nil { |
| if value.Variable == "LOCAL_PATH" { |
| return &bpparser.Value{ |
| Type: bpparser.String, |
| StringValue: ".", |
| }, nil |
| } |
| return nil, nil |
| } |
| |
| if value.Expression.Operator != '+' { |
| return nil, nil |
| } |
| |
| firstOperand := value.Expression.Args[0] |
| secondOperand := value.Expression.Args[1] |
| if firstOperand.Type != bpparser.String { |
| return nil, nil |
| } |
| |
| if firstOperand.Expression != nil { |
| return nil, nil |
| } |
| |
| if firstOperand.Variable != "LOCAL_PATH" { |
| return nil, nil |
| } |
| |
| if secondOperand.Expression == nil && secondOperand.Variable == "" { |
| if strings.HasPrefix(secondOperand.StringValue, "/") { |
| secondOperand.StringValue = secondOperand.StringValue[1:] |
| } |
| } |
| return &secondOperand, nil |
| } |
| |
| func emptyList(value *bpparser.Value) bool { |
| return value.Type == bpparser.List && value.Expression == nil && value.Variable == "" && |
| len(value.ListValue) == 0 |
| } |
| |
| func splitLocalGlobal(file *bpFile, val *bpparser.Value) (local, global *bpparser.Value, err error) { |
| local = &bpparser.Value{ |
| Type: bpparser.List, |
| } |
| global = &bpparser.Value{ |
| Type: bpparser.List, |
| } |
| |
| if val.Expression != nil { |
| localA, globalA, err := splitLocalGlobal(file, &val.Expression.Args[0]) |
| if err != nil { |
| return nil, nil, err |
| } |
| |
| localB, globalB, err := splitLocalGlobal(file, &val.Expression.Args[1]) |
| if err != nil { |
| return nil, nil, err |
| } |
| |
| if emptyList(localA) { |
| local = localB |
| } else if emptyList(localB) { |
| local = localA |
| } else { |
| localExpression := *val.Expression |
| local.Expression = &localExpression |
| local.Expression.Args = [2]bpparser.Value{*localA, *localB} |
| } |
| |
| if emptyList(globalA) { |
| global = globalB |
| } else if emptyList(globalB) { |
| global = globalA |
| } else { |
| globalExpression := *val.Expression |
| global.Expression = &globalExpression |
| global.Expression.Args = [2]bpparser.Value{*globalA, *globalB} |
| } |
| } else if val.Variable != "" { |
| if val.Variable == "LOCAL_PATH" { |
| local.ListValue = append(local.ListValue, bpparser.Value{ |
| Type: bpparser.String, |
| StringValue: ".", |
| }) |
| } else { |
| global.Variable = val.Variable |
| } |
| } else { |
| for _, v := range val.ListValue { |
| localPath, err := localAbsPath(v) |
| if err != nil { |
| return nil, nil, err |
| } |
| if localPath != nil { |
| local.ListValue = append(local.ListValue, *localPath) |
| } else { |
| global.ListValue = append(global.ListValue, v) |
| } |
| } |
| } |
| |
| return local, global, nil |
| } |
| |
| func localIncludeDirs(file *bpFile, prefix string, value *mkparser.MakeString, appendVariable bool) error { |
| val, err := makeVariableToBlueprint(file, value, bpparser.List) |
| if err != nil { |
| return err |
| } |
| |
| local, global, err := splitLocalGlobal(file, val) |
| if err != nil { |
| return err |
| } |
| |
| if len(global.ListValue) > 0 || global.Expression != nil || global.Variable != "" { |
| err = setVariable(file, appendVariable, prefix, "include_dirs", global, true) |
| if err != nil { |
| return err |
| } |
| } |
| |
| if len(local.ListValue) > 0 || local.Expression != nil || local.Variable != "" { |
| err = setVariable(file, appendVariable, prefix, "local_include_dirs", local, true) |
| if err != nil { |
| return err |
| } |
| } |
| |
| return nil |
| } |
| |
| func exportIncludeDirs(file *bpFile, prefix string, value *mkparser.MakeString, appendVariable bool) error { |
| val, err := makeVariableToBlueprint(file, value, bpparser.List) |
| if err != nil { |
| return err |
| } |
| |
| local, global, err := splitLocalGlobal(file, val) |
| if err != nil { |
| return err |
| } |
| |
| if len(local.ListValue) > 0 || local.Expression != nil || local.Variable != "" { |
| err = setVariable(file, appendVariable, prefix, "export_include_dirs", local, true) |
| if err != nil { |
| return err |
| } |
| appendVariable = true |
| } |
| |
| // Add any paths that could not be converted to local relative paths to export_include_dirs |
| // anyways, they will cause an error if they don't exist and can be fixed manually. |
| if len(global.ListValue) > 0 || global.Expression != nil || global.Variable != "" { |
| err = setVariable(file, appendVariable, prefix, "export_include_dirs", global, true) |
| if err != nil { |
| return err |
| } |
| } |
| |
| return nil |
| } |
| |
| func stem(file *bpFile, prefix string, value *mkparser.MakeString, appendVariable bool) error { |
| val, err := makeVariableToBlueprint(file, value, bpparser.String) |
| if err != nil { |
| return err |
| } |
| varName := "stem" |
| |
| if val.Expression != nil && val.Expression.Operator == '+' && |
| val.Expression.Args[0].Variable == "LOCAL_MODULE" { |
| varName = "suffix" |
| val = &val.Expression.Args[1] |
| } |
| |
| return setVariable(file, appendVariable, prefix, varName, val, true) |
| } |
| |
| func hostOs(file *bpFile, prefix string, value *mkparser.MakeString, appendVariable bool) error { |
| val, err := makeVariableToBlueprint(file, value, bpparser.List) |
| if err != nil { |
| return err |
| } |
| |
| inList := func(s string) bool { |
| for _, v := range val.ListValue { |
| if v.StringValue == s { |
| return true |
| } |
| } |
| return false |
| } |
| |
| falseValue := &bpparser.Value{ |
| Type: bpparser.Bool, |
| BoolValue: false, |
| } |
| |
| trueValue := &bpparser.Value{ |
| Type: bpparser.Bool, |
| BoolValue: true, |
| } |
| |
| if inList("windows") { |
| err = setVariable(file, appendVariable, "target.windows", "enabled", trueValue, true) |
| } |
| |
| if !inList("linux") && err == nil { |
| err = setVariable(file, appendVariable, "target.linux", "enabled", falseValue, true) |
| } |
| |
| if !inList("darwin") && err == nil { |
| err = setVariable(file, appendVariable, "target.darwin", "enabled", falseValue, true) |
| } |
| |
| return err |
| } |
| |
| var deleteProperties = map[string]struct{}{ |
| "LOCAL_CPP_EXTENSION": struct{}{}, |
| } |
| |
| var propertyPrefixes = map[string]string{ |
| "arm": "arch.arm", |
| "arm64": "arm.arm64", |
| "mips": "arch.mips", |
| "mips64": "arch.mips64", |
| "x86": "arch.x86", |
| "x86_64": "arch.x86_64", |
| "32": "multilib.lib32", |
| "64": "multilib.lib64", |
| } |
| |
| var conditionalTranslations = map[string]map[bool]string{ |
| "($(HOST_OS),darwin)": { |
| true: "target.darwin", |
| false: "target.not_darwin"}, |
| "($(HOST_OS), darwin)": { |
| true: "target.darwin", |
| false: "target.not_darwin"}, |
| "($(HOST_OS),windows)": { |
| true: "target.windows", |
| false: "target.not_windows"}, |
| "($(HOST_OS), windows)": { |
| true: "target.windows", |
| false: "target.not_windows"}, |
| "($(HOST_OS),linux)": { |
| true: "target.linux", |
| false: "target.not_linux"}, |
| "($(HOST_OS), linux)": { |
| true: "target.linux", |
| false: "target.not_linux"}, |
| "($(BUILD_OS),darwin)": { |
| true: "target.darwin", |
| false: "target.not_darwin"}, |
| "($(BUILD_OS), darwin)": { |
| true: "target.darwin", |
| false: "target.not_darwin"}, |
| "($(BUILD_OS),linux)": { |
| true: "target.linux", |
| false: "target.not_linux"}, |
| "($(BUILD_OS), linux)": { |
| true: "target.linux", |
| false: "target.not_linux"}, |
| "USE_MINGW": { |
| true: "target.windows", |
| false: "target.not_windows"}, |
| "(,$(TARGET_BUILD_APPS))": { |
| false: "product_variables.unbundled_build", |
| }, |
| } |
| |
| func mydir(args []string) string { |
| return "." |
| } |
| |
| func allJavaFilesUnder(args []string) string { |
| dir := "" |
| if len(args) > 0 { |
| dir = strings.TrimSpace(args[0]) |
| } |
| |
| return fmt.Sprintf("%s/**/*.java", dir) |
| } |
| |
| func allSubdirJavaFiles(args []string) string { |
| return "**/*.java" |
| } |
| |
| var moduleTypes = map[string]string{ |
| "BUILD_SHARED_LIBRARY": "cc_library_shared", |
| "BUILD_STATIC_LIBRARY": "cc_library_static", |
| "BUILD_HOST_SHARED_LIBRARY": "cc_library_host_shared", |
| "BUILD_HOST_STATIC_LIBRARY": "cc_library_host_static", |
| "BUILD_EXECUTABLE": "cc_binary", |
| "BUILD_HOST_EXECUTABLE": "cc_binary_host", |
| "BUILD_NATIVE_TEST": "cc_test", |
| "BUILD_HOST_NATIVE_TEST": "cc_test_host", |
| "BUILD_NATIVE_BENCHMARK": "cc_benchmark", |
| "BUILD_HOST_NATIVE_BENCHMARK": "cc_benchmark_host", |
| |
| "BUILD_JAVA_LIBRARY": "java_library", |
| "BUILD_STATIC_JAVA_LIBRARY": "java_library_static", |
| "BUILD_HOST_JAVA_LIBRARY": "java_library_host", |
| "BUILD_HOST_DALVIK_JAVA_LIBRARY": "java_library_host_dalvik", |
| "BUILD_PACKAGE": "android_app", |
| |
| "BUILD_PREBUILT": "prebuilt", |
| } |
| |
| var soongModuleTypes = map[string]bool{} |
| |
| func androidScope() mkparser.Scope { |
| globalScope := mkparser.NewScope(nil) |
| globalScope.Set("CLEAR_VARS", clear_vars) |
| globalScope.SetFunc("my-dir", mydir) |
| globalScope.SetFunc("all-java-files-under", allJavaFilesUnder) |
| globalScope.SetFunc("all-subdir-java-files", allSubdirJavaFiles) |
| |
| for k, v := range moduleTypes { |
| globalScope.Set(k, v) |
| soongModuleTypes[v] = true |
| } |
| |
| return globalScope |
| } |