1package main 2 3import ( 4 mkparser "android/soong/androidmk/parser" 5 "fmt" 6 "strings" 7 8 bpparser "github.com/google/blueprint/parser" 9) 10 11const ( 12 clear_vars = "__android_mk_clear_vars" 13) 14 15var standardProperties = map[string]struct { 16 string 17 bpparser.ValueType 18}{ 19 // String properties 20 "LOCAL_MODULE": {"name", bpparser.String}, 21 "LOCAL_MODULE_CLASS": {"class", bpparser.String}, 22 "LOCAL_CXX_STL": {"stl", bpparser.String}, 23 "LOCAL_STRIP_MODULE": {"strip", bpparser.String}, 24 "LOCAL_MULTILIB": {"compile_multilib", bpparser.String}, 25 "LOCAL_ARM_MODE_HACK": {"instruction_set", bpparser.String}, 26 "LOCAL_SDK_VERSION": {"sdk_version", bpparser.String}, 27 "LOCAL_NDK_STL_VARIANT": {"stl", bpparser.String}, 28 "LOCAL_JAR_MANIFEST": {"manifest", bpparser.String}, 29 "LOCAL_JARJAR_RULES": {"jarjar_rules", bpparser.String}, 30 "LOCAL_CERTIFICATE": {"certificate", bpparser.String}, 31 "LOCAL_PACKAGE_NAME": {"name", bpparser.String}, 32 "LOCAL_MODULE_RELATIVE_PATH": {"relative_install_path", bpparser.String}, 33 34 // List properties 35 "LOCAL_SRC_FILES": {"srcs", bpparser.List}, 36 "LOCAL_SHARED_LIBRARIES": {"shared_libs", bpparser.List}, 37 "LOCAL_STATIC_LIBRARIES": {"static_libs", bpparser.List}, 38 "LOCAL_WHOLE_STATIC_LIBRARIES": {"whole_static_libs", bpparser.List}, 39 "LOCAL_SYSTEM_SHARED_LIBRARIES": {"system_shared_libs", bpparser.List}, 40 "LOCAL_ASFLAGS": {"asflags", bpparser.List}, 41 "LOCAL_CLANG_ASFLAGS": {"clang_asflags", bpparser.List}, 42 "LOCAL_CFLAGS": {"cflags", bpparser.List}, 43 "LOCAL_CONLYFLAGS": {"conlyflags", bpparser.List}, 44 "LOCAL_CPPFLAGS": {"cppflags", bpparser.List}, 45 "LOCAL_LDFLAGS": {"ldflags", bpparser.List}, 46 "LOCAL_REQUIRED_MODULES": {"required", bpparser.List}, 47 "LOCAL_MODULE_TAGS": {"tags", bpparser.List}, 48 "LOCAL_LDLIBS": {"host_ldlibs", bpparser.List}, 49 "LOCAL_CLANG_CFLAGS": {"clang_cflags", bpparser.List}, 50 "LOCAL_YACCFLAGS": {"yaccflags", bpparser.List}, 51 "LOCAL_SANITIZE": {"sanitize", bpparser.List}, 52 "LOCAL_SANITIZE_RECOVER": {"sanitize_recover", bpparser.List}, 53 54 "LOCAL_JAVA_RESOURCE_DIRS": {"java_resource_dirs", bpparser.List}, 55 "LOCAL_JAVACFLAGS": {"javacflags", bpparser.List}, 56 "LOCAL_DX_FLAGS": {"dxflags", bpparser.List}, 57 "LOCAL_JAVA_LIBRARIES": {"java_libs", bpparser.List}, 58 "LOCAL_STATIC_JAVA_LIBRARIES": {"java_static_libs", bpparser.List}, 59 "LOCAL_AIDL_INCLUDES": {"aidl_includes", bpparser.List}, 60 "LOCAL_AAPT_FLAGS": {"aaptflags", bpparser.List}, 61 "LOCAL_PACKAGE_SPLITS": {"package_splits", bpparser.List}, 62 63 // Bool properties 64 "LOCAL_IS_HOST_MODULE": {"host", bpparser.Bool}, 65 "LOCAL_CLANG": {"clang", bpparser.Bool}, 66 "LOCAL_FORCE_STATIC_EXECUTABLE": {"static", bpparser.Bool}, 67 "LOCAL_NATIVE_COVERAGE": {"native_coverage", bpparser.Bool}, 68 "LOCAL_NO_CRT": {"nocrt", bpparser.Bool}, 69 "LOCAL_ALLOW_UNDEFINED_SYMBOLS": {"allow_undefined_symbols", bpparser.Bool}, 70 "LOCAL_RTTI_FLAG": {"rtti", bpparser.Bool}, 71 72 "LOCAL_NO_STANDARD_LIBRARIES": {"no_standard_libraries", bpparser.Bool}, 73 74 "LOCAL_EXPORT_PACKAGE_RESOURCES": {"export_package_resources", bpparser.Bool}, 75} 76 77var rewriteProperties = map[string]struct { 78 f func(file *bpFile, prefix string, value *mkparser.MakeString, append bool) error 79}{ 80 "LOCAL_C_INCLUDES": {localIncludeDirs}, 81 "LOCAL_EXPORT_C_INCLUDE_DIRS": {exportIncludeDirs}, 82 "LOCAL_MODULE_STEM": {stem}, 83 "LOCAL_MODULE_HOST_OS": {hostOs}, 84} 85 86func localAbsPath(value bpparser.Value) (*bpparser.Value, error) { 87 if value.Type != bpparser.String { 88 return nil, fmt.Errorf("isLocalAbsPath expected a string, got %d", value.Type) 89 } 90 91 if value.Expression == nil { 92 if value.Variable == "LOCAL_PATH" { 93 return &bpparser.Value{ 94 Type: bpparser.String, 95 StringValue: ".", 96 }, nil 97 } 98 return nil, nil 99 } 100 101 if value.Expression.Operator != '+' { 102 return nil, nil 103 } 104 105 firstOperand := value.Expression.Args[0] 106 secondOperand := value.Expression.Args[1] 107 if firstOperand.Type != bpparser.String { 108 return nil, nil 109 } 110 111 if firstOperand.Expression != nil { 112 return nil, nil 113 } 114 115 if firstOperand.Variable != "LOCAL_PATH" { 116 return nil, nil 117 } 118 119 if secondOperand.Expression == nil && secondOperand.Variable == "" { 120 if strings.HasPrefix(secondOperand.StringValue, "/") { 121 secondOperand.StringValue = secondOperand.StringValue[1:] 122 } 123 } 124 return &secondOperand, nil 125} 126 127func emptyList(value *bpparser.Value) bool { 128 return value.Type == bpparser.List && value.Expression == nil && value.Variable == "" && 129 len(value.ListValue) == 0 130} 131 132func splitLocalGlobal(file *bpFile, val *bpparser.Value) (local, global *bpparser.Value, err error) { 133 local = &bpparser.Value{ 134 Type: bpparser.List, 135 } 136 global = &bpparser.Value{ 137 Type: bpparser.List, 138 } 139 140 if val.Expression != nil { 141 localA, globalA, err := splitLocalGlobal(file, &val.Expression.Args[0]) 142 if err != nil { 143 return nil, nil, err 144 } 145 146 localB, globalB, err := splitLocalGlobal(file, &val.Expression.Args[1]) 147 if err != nil { 148 return nil, nil, err 149 } 150 151 if emptyList(localA) { 152 local = localB 153 } else if emptyList(localB) { 154 local = localA 155 } else { 156 localExpression := *val.Expression 157 local.Expression = &localExpression 158 local.Expression.Args = [2]bpparser.Value{*localA, *localB} 159 } 160 161 if emptyList(globalA) { 162 global = globalB 163 } else if emptyList(globalB) { 164 global = globalA 165 } else { 166 globalExpression := *val.Expression 167 global.Expression = &globalExpression 168 global.Expression.Args = [2]bpparser.Value{*globalA, *globalB} 169 } 170 } else if val.Variable != "" { 171 if val.Variable == "LOCAL_PATH" { 172 local.ListValue = append(local.ListValue, bpparser.Value{ 173 Type: bpparser.String, 174 StringValue: ".", 175 }) 176 } else { 177 global.Variable = val.Variable 178 } 179 } else { 180 for _, v := range val.ListValue { 181 localPath, err := localAbsPath(v) 182 if err != nil { 183 return nil, nil, err 184 } 185 if localPath != nil { 186 local.ListValue = append(local.ListValue, *localPath) 187 } else { 188 global.ListValue = append(global.ListValue, v) 189 } 190 } 191 } 192 193 return local, global, nil 194} 195 196func localIncludeDirs(file *bpFile, prefix string, value *mkparser.MakeString, appendVariable bool) error { 197 val, err := makeVariableToBlueprint(file, value, bpparser.List) 198 if err != nil { 199 return err 200 } 201 202 local, global, err := splitLocalGlobal(file, val) 203 if err != nil { 204 return err 205 } 206 207 if len(global.ListValue) > 0 || global.Expression != nil || global.Variable != "" { 208 err = setVariable(file, appendVariable, prefix, "include_dirs", global, true) 209 if err != nil { 210 return err 211 } 212 } 213 214 if len(local.ListValue) > 0 || local.Expression != nil || local.Variable != "" { 215 err = setVariable(file, appendVariable, prefix, "local_include_dirs", local, true) 216 if err != nil { 217 return err 218 } 219 } 220 221 return nil 222} 223 224func exportIncludeDirs(file *bpFile, prefix string, value *mkparser.MakeString, appendVariable bool) error { 225 val, err := makeVariableToBlueprint(file, value, bpparser.List) 226 if err != nil { 227 return err 228 } 229 230 local, global, err := splitLocalGlobal(file, val) 231 if err != nil { 232 return err 233 } 234 235 if len(local.ListValue) > 0 || local.Expression != nil || local.Variable != "" { 236 err = setVariable(file, appendVariable, prefix, "export_include_dirs", local, true) 237 if err != nil { 238 return err 239 } 240 appendVariable = true 241 } 242 243 // Add any paths that could not be converted to local relative paths to export_include_dirs 244 // anyways, they will cause an error if they don't exist and can be fixed manually. 245 if len(global.ListValue) > 0 || global.Expression != nil || global.Variable != "" { 246 err = setVariable(file, appendVariable, prefix, "export_include_dirs", global, true) 247 if err != nil { 248 return err 249 } 250 } 251 252 return nil 253} 254 255func stem(file *bpFile, prefix string, value *mkparser.MakeString, appendVariable bool) error { 256 val, err := makeVariableToBlueprint(file, value, bpparser.String) 257 if err != nil { 258 return err 259 } 260 varName := "stem" 261 262 if val.Expression != nil && val.Expression.Operator == '+' && 263 val.Expression.Args[0].Variable == "LOCAL_MODULE" { 264 varName = "suffix" 265 val = &val.Expression.Args[1] 266 } 267 268 return setVariable(file, appendVariable, prefix, varName, val, true) 269} 270 271func hostOs(file *bpFile, prefix string, value *mkparser.MakeString, appendVariable bool) error { 272 val, err := makeVariableToBlueprint(file, value, bpparser.List) 273 if err != nil { 274 return err 275 } 276 277 inList := func(s string) bool { 278 for _, v := range val.ListValue { 279 if v.StringValue == s { 280 return true 281 } 282 } 283 return false 284 } 285 286 falseValue := &bpparser.Value{ 287 Type: bpparser.Bool, 288 BoolValue: false, 289 } 290 291 trueValue := &bpparser.Value{ 292 Type: bpparser.Bool, 293 BoolValue: true, 294 } 295 296 if inList("windows") { 297 err = setVariable(file, appendVariable, "target.windows", "enabled", trueValue, true) 298 } 299 300 if !inList("linux") && err == nil { 301 err = setVariable(file, appendVariable, "target.linux", "enabled", falseValue, true) 302 } 303 304 if !inList("darwin") && err == nil { 305 err = setVariable(file, appendVariable, "target.darwin", "enabled", falseValue, true) 306 } 307 308 return err 309} 310 311var deleteProperties = map[string]struct{}{ 312 "LOCAL_CPP_EXTENSION": struct{}{}, 313} 314 315var propertyPrefixes = map[string]string{ 316 "arm": "arch.arm", 317 "arm64": "arm.arm64", 318 "mips": "arch.mips", 319 "mips64": "arch.mips64", 320 "x86": "arch.x86", 321 "x86_64": "arch.x86_64", 322 "32": "multilib.lib32", 323 "64": "multilib.lib64", 324} 325 326var conditionalTranslations = map[string]map[bool]string{ 327 "($(HOST_OS),darwin)": { 328 true: "target.darwin", 329 false: "target.not_darwin"}, 330 "($(HOST_OS), darwin)": { 331 true: "target.darwin", 332 false: "target.not_darwin"}, 333 "($(HOST_OS),windows)": { 334 true: "target.windows", 335 false: "target.not_windows"}, 336 "($(HOST_OS), windows)": { 337 true: "target.windows", 338 false: "target.not_windows"}, 339 "($(HOST_OS),linux)": { 340 true: "target.linux", 341 false: "target.not_linux"}, 342 "($(HOST_OS), linux)": { 343 true: "target.linux", 344 false: "target.not_linux"}, 345 "($(BUILD_OS),darwin)": { 346 true: "target.darwin", 347 false: "target.not_darwin"}, 348 "($(BUILD_OS), darwin)": { 349 true: "target.darwin", 350 false: "target.not_darwin"}, 351 "($(BUILD_OS),linux)": { 352 true: "target.linux", 353 false: "target.not_linux"}, 354 "($(BUILD_OS), linux)": { 355 true: "target.linux", 356 false: "target.not_linux"}, 357 "USE_MINGW": { 358 true: "target.windows", 359 false: "target.not_windows"}, 360 "(,$(TARGET_BUILD_APPS))": { 361 false: "product_variables.unbundled_build", 362 }, 363} 364 365func mydir(args []string) string { 366 return "." 367} 368 369func allJavaFilesUnder(args []string) string { 370 dir := "" 371 if len(args) > 0 { 372 dir = strings.TrimSpace(args[0]) 373 } 374 375 return fmt.Sprintf("%s/**/*.java", dir) 376} 377 378func allSubdirJavaFiles(args []string) string { 379 return "**/*.java" 380} 381 382var moduleTypes = map[string]string{ 383 "BUILD_SHARED_LIBRARY": "cc_library_shared", 384 "BUILD_STATIC_LIBRARY": "cc_library_static", 385 "BUILD_HOST_SHARED_LIBRARY": "cc_library_host_shared", 386 "BUILD_HOST_STATIC_LIBRARY": "cc_library_host_static", 387 "BUILD_EXECUTABLE": "cc_binary", 388 "BUILD_HOST_EXECUTABLE": "cc_binary_host", 389 "BUILD_NATIVE_TEST": "cc_test", 390 "BUILD_HOST_NATIVE_TEST": "cc_test_host", 391 "BUILD_NATIVE_BENCHMARK": "cc_benchmark", 392 "BUILD_HOST_NATIVE_BENCHMARK": "cc_benchmark_host", 393 394 "BUILD_JAVA_LIBRARY": "java_library", 395 "BUILD_STATIC_JAVA_LIBRARY": "java_library_static", 396 "BUILD_HOST_JAVA_LIBRARY": "java_library_host", 397 "BUILD_HOST_DALVIK_JAVA_LIBRARY": "java_library_host_dalvik", 398 "BUILD_PACKAGE": "android_app", 399 400 "BUILD_PREBUILT": "prebuilt", 401} 402 403var soongModuleTypes = map[string]bool{} 404 405func androidScope() mkparser.Scope { 406 globalScope := mkparser.NewScope(nil) 407 globalScope.Set("CLEAR_VARS", clear_vars) 408 globalScope.SetFunc("my-dir", mydir) 409 globalScope.SetFunc("all-java-files-under", allJavaFilesUnder) 410 globalScope.SetFunc("all-subdir-java-files", allSubdirJavaFiles) 411 412 for k, v := range moduleTypes { 413 globalScope.Set(k, v) 414 soongModuleTypes[v] = true 415 } 416 417 return globalScope 418} 419