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 androidmk 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 clearVarsPath = "__android_mk_clear_vars" 28 includeIgnoredPath = "__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 trueValue = &bpparser.Bool{ 44 Value: true, 45} 46 47var rewriteProperties = map[string](func(variableAssignmentContext) error){ 48 // custom functions 49 "LOCAL_32_BIT_ONLY": local32BitOnly, 50 "LOCAL_AIDL_INCLUDES": localAidlIncludes, 51 "LOCAL_ASSET_DIR": localizePathList("asset_dirs"), 52 "LOCAL_C_INCLUDES": localIncludeDirs, 53 "LOCAL_EXPORT_C_INCLUDE_DIRS": exportIncludeDirs, 54 "LOCAL_JARJAR_RULES": localizePath("jarjar_rules"), 55 "LOCAL_LDFLAGS": ldflags, 56 "LOCAL_MODULE_CLASS": prebuiltClass, 57 "LOCAL_MODULE_STEM": stem, 58 "LOCAL_MODULE_HOST_OS": hostOs, 59 "LOCAL_RESOURCE_DIR": localizePathList("resource_dirs"), 60 "LOCAL_SANITIZE": sanitize(""), 61 "LOCAL_SANITIZE_DIAG": sanitize("diag."), 62 "LOCAL_STRIP_MODULE": strip(), 63 "LOCAL_CFLAGS": cflags, 64 "LOCAL_UNINSTALLABLE_MODULE": invert("installable"), 65 "LOCAL_PROGUARD_ENABLED": proguardEnabled, 66 "LOCAL_MODULE_PATH": prebuiltModulePath, 67 "LOCAL_REPLACE_PREBUILT_APK_INSTALLED": prebuiltPreprocessed, 68 69 // composite functions 70 "LOCAL_MODULE_TAGS": includeVariableIf(bpVariable{"tags", bpparser.ListType}, not(valueDumpEquals("optional"))), 71 72 // skip functions 73 "LOCAL_ADDITIONAL_DEPENDENCIES": skip, // TODO: check for only .mk files? 74 "LOCAL_CPP_EXTENSION": skip, 75 "LOCAL_MODULE_SUFFIX": skip, // TODO 76 "LOCAL_PATH": skip, // Nothing to do, except maybe avoid the "./" in paths? 77 "LOCAL_PRELINK_MODULE": skip, // Already phased out 78 "LOCAL_BUILT_MODULE_STEM": skip, 79 "LOCAL_USE_AAPT2": skip, // Always enabled in Soong 80 "LOCAL_JAR_EXCLUDE_FILES": skip, // Soong never excludes files from jars 81 82 "LOCAL_ANNOTATION_PROCESSOR_CLASSES": skip, // Soong gets the processor classes from the plugin 83 "LOCAL_CTS_TEST_PACKAGE": skip, // Obsolete 84 "LOCAL_JACK_ENABLED": skip, // Obselete 85 "LOCAL_JACK_FLAGS": skip, // Obselete 86} 87 88// adds a group of properties all having the same type 89func addStandardProperties(propertyType bpparser.Type, properties map[string]string) { 90 for key, val := range properties { 91 rewriteProperties[key] = includeVariable(bpVariable{val, propertyType}) 92 } 93} 94 95func init() { 96 addStandardProperties(bpparser.StringType, 97 map[string]string{ 98 "LOCAL_MODULE": "name", 99 "LOCAL_CXX_STL": "stl", 100 "LOCAL_MULTILIB": "compile_multilib", 101 "LOCAL_ARM_MODE_HACK": "instruction_set", 102 "LOCAL_SDK_VERSION": "sdk_version", 103 "LOCAL_MIN_SDK_VERSION": "min_sdk_version", 104 "LOCAL_NDK_STL_VARIANT": "stl", 105 "LOCAL_JAR_MANIFEST": "manifest", 106 "LOCAL_CERTIFICATE": "certificate", 107 "LOCAL_PACKAGE_NAME": "name", 108 "LOCAL_MODULE_RELATIVE_PATH": "relative_install_path", 109 "LOCAL_PROTOC_OPTIMIZE_TYPE": "proto.type", 110 "LOCAL_MODULE_OWNER": "owner", 111 "LOCAL_RENDERSCRIPT_TARGET_API": "renderscript.target_api", 112 "LOCAL_NOTICE_FILE": "notice", 113 "LOCAL_JAVA_LANGUAGE_VERSION": "java_version", 114 "LOCAL_INSTRUMENTATION_FOR": "instrumentation_for", 115 "LOCAL_MANIFEST_FILE": "manifest", 116 117 "LOCAL_DEX_PREOPT_PROFILE_CLASS_LISTING": "dex_preopt.profile", 118 "LOCAL_TEST_CONFIG": "test_config", 119 "LOCAL_RRO_THEME": "theme", 120 }) 121 addStandardProperties(bpparser.ListType, 122 map[string]string{ 123 "LOCAL_SRC_FILES": "srcs", 124 "LOCAL_SRC_FILES_EXCLUDE": "exclude_srcs", 125 "LOCAL_HEADER_LIBRARIES": "header_libs", 126 "LOCAL_SHARED_LIBRARIES": "shared_libs", 127 "LOCAL_STATIC_LIBRARIES": "static_libs", 128 "LOCAL_WHOLE_STATIC_LIBRARIES": "whole_static_libs", 129 "LOCAL_SYSTEM_SHARED_LIBRARIES": "system_shared_libs", 130 "LOCAL_ASFLAGS": "asflags", 131 "LOCAL_CLANG_ASFLAGS": "clang_asflags", 132 "LOCAL_COMPATIBILITY_SUPPORT_FILES": "data", 133 "LOCAL_CONLYFLAGS": "conlyflags", 134 "LOCAL_CPPFLAGS": "cppflags", 135 "LOCAL_REQUIRED_MODULES": "required", 136 "LOCAL_HOST_REQUIRED_MODULES": "host_required", 137 "LOCAL_TARGET_REQUIRED_MODULES": "target_required", 138 "LOCAL_OVERRIDES_MODULES": "overrides", 139 "LOCAL_LDLIBS": "host_ldlibs", 140 "LOCAL_CLANG_CFLAGS": "clang_cflags", 141 "LOCAL_YACCFLAGS": "yacc.flags", 142 "LOCAL_SANITIZE_RECOVER": "sanitize.recover", 143 "LOCAL_LOGTAGS_FILES": "logtags", 144 "LOCAL_EXPORT_HEADER_LIBRARY_HEADERS": "export_header_lib_headers", 145 "LOCAL_EXPORT_SHARED_LIBRARY_HEADERS": "export_shared_lib_headers", 146 "LOCAL_EXPORT_STATIC_LIBRARY_HEADERS": "export_static_lib_headers", 147 "LOCAL_INIT_RC": "init_rc", 148 "LOCAL_VINTF_FRAGMENTS": "vintf_fragments", 149 "LOCAL_TIDY_FLAGS": "tidy_flags", 150 // TODO: This is comma-separated, not space-separated 151 "LOCAL_TIDY_CHECKS": "tidy_checks", 152 "LOCAL_RENDERSCRIPT_INCLUDES": "renderscript.include_dirs", 153 "LOCAL_RENDERSCRIPT_FLAGS": "renderscript.flags", 154 155 "LOCAL_JAVA_RESOURCE_DIRS": "java_resource_dirs", 156 "LOCAL_JAVA_RESOURCE_FILES": "java_resources", 157 "LOCAL_JAVACFLAGS": "javacflags", 158 "LOCAL_ERROR_PRONE_FLAGS": "errorprone.javacflags", 159 "LOCAL_DX_FLAGS": "dxflags", 160 "LOCAL_JAVA_LIBRARIES": "libs", 161 "LOCAL_STATIC_JAVA_LIBRARIES": "static_libs", 162 "LOCAL_JNI_SHARED_LIBRARIES": "jni_libs", 163 "LOCAL_AAPT_FLAGS": "aaptflags", 164 "LOCAL_PACKAGE_SPLITS": "package_splits", 165 "LOCAL_COMPATIBILITY_SUITE": "test_suites", 166 "LOCAL_OVERRIDES_PACKAGES": "overrides", 167 168 "LOCAL_ANNOTATION_PROCESSORS": "plugins", 169 170 "LOCAL_PROGUARD_FLAGS": "optimize.proguard_flags", 171 "LOCAL_PROGUARD_FLAG_FILES": "optimize.proguard_flags_files", 172 173 // These will be rewritten to libs/static_libs by bpfix, after their presence is used to convert 174 // java_library_static to android_library. 175 "LOCAL_SHARED_ANDROID_LIBRARIES": "android_libs", 176 "LOCAL_STATIC_ANDROID_LIBRARIES": "android_static_libs", 177 "LOCAL_ADDITIONAL_CERTIFICATES": "additional_certificates", 178 179 // Jacoco filters: 180 "LOCAL_JACK_COVERAGE_INCLUDE_FILTER": "jacoco.include_filter", 181 "LOCAL_JACK_COVERAGE_EXCLUDE_FILTER": "jacoco.exclude_filter", 182 183 "LOCAL_FULL_LIBS_MANIFEST_FILES": "additional_manifests", 184 }) 185 186 addStandardProperties(bpparser.BoolType, 187 map[string]string{ 188 // Bool properties 189 "LOCAL_IS_HOST_MODULE": "host", 190 "LOCAL_CLANG": "clang", 191 "LOCAL_FORCE_STATIC_EXECUTABLE": "static_executable", 192 "LOCAL_NATIVE_COVERAGE": "native_coverage", 193 "LOCAL_NO_CRT": "nocrt", 194 "LOCAL_ALLOW_UNDEFINED_SYMBOLS": "allow_undefined_symbols", 195 "LOCAL_RTTI_FLAG": "rtti", 196 "LOCAL_PACK_MODULE_RELOCATIONS": "pack_relocations", 197 "LOCAL_TIDY": "tidy", 198 "LOCAL_USE_CLANG_LLD": "use_clang_lld", 199 "LOCAL_PROPRIETARY_MODULE": "proprietary", 200 "LOCAL_VENDOR_MODULE": "vendor", 201 "LOCAL_ODM_MODULE": "device_specific", 202 "LOCAL_PRODUCT_MODULE": "product_specific", 203 "LOCAL_SYSTEM_EXT_MODULE": "system_ext_specific", 204 "LOCAL_EXPORT_PACKAGE_RESOURCES": "export_package_resources", 205 "LOCAL_PRIVILEGED_MODULE": "privileged", 206 "LOCAL_AAPT_INCLUDE_ALL_RESOURCES": "aapt_include_all_resources", 207 "LOCAL_DONT_MERGE_MANIFESTS": "dont_merge_manifests", 208 "LOCAL_USE_EMBEDDED_NATIVE_LIBS": "use_embedded_native_libs", 209 "LOCAL_USE_EMBEDDED_DEX": "use_embedded_dex", 210 211 "LOCAL_DEX_PREOPT": "dex_preopt.enabled", 212 "LOCAL_DEX_PREOPT_APP_IMAGE": "dex_preopt.app_image", 213 "LOCAL_DEX_PREOPT_GENERATE_PROFILE": "dex_preopt.profile_guided", 214 215 "LOCAL_PRIVATE_PLATFORM_APIS": "platform_apis", 216 "LOCAL_JETIFIER_ENABLED": "jetifier", 217 218 "LOCAL_IS_UNIT_TEST": "unit_test", 219 220 "LOCAL_ENFORCE_USES_LIBRARIES": "enforce_uses_libs", 221 }) 222} 223 224type listSplitFunc func(bpparser.Expression) (string, bpparser.Expression, error) 225 226func emptyList(value bpparser.Expression) bool { 227 if list, ok := value.(*bpparser.List); ok { 228 return len(list.Values) == 0 229 } 230 return false 231} 232 233func splitBpList(val bpparser.Expression, keyFunc listSplitFunc) (lists map[string]bpparser.Expression, err error) { 234 lists = make(map[string]bpparser.Expression) 235 236 switch val := val.(type) { 237 case *bpparser.Operator: 238 listsA, err := splitBpList(val.Args[0], keyFunc) 239 if err != nil { 240 return nil, err 241 } 242 243 listsB, err := splitBpList(val.Args[1], keyFunc) 244 if err != nil { 245 return nil, err 246 } 247 248 for k, v := range listsA { 249 if !emptyList(v) { 250 lists[k] = v 251 } 252 } 253 254 for k, vB := range listsB { 255 if emptyList(vB) { 256 continue 257 } 258 259 if vA, ok := lists[k]; ok { 260 expression := val.Copy().(*bpparser.Operator) 261 expression.Args = [2]bpparser.Expression{vA, vB} 262 lists[k] = expression 263 } else { 264 lists[k] = vB 265 } 266 } 267 case *bpparser.Variable: 268 key, value, err := keyFunc(val) 269 if err != nil { 270 return nil, err 271 } 272 if value.Type() == bpparser.ListType { 273 lists[key] = value 274 } else { 275 lists[key] = &bpparser.List{ 276 Values: []bpparser.Expression{value}, 277 } 278 } 279 case *bpparser.List: 280 for _, v := range val.Values { 281 key, value, err := keyFunc(v) 282 if err != nil { 283 return nil, err 284 } 285 l := lists[key] 286 if l == nil { 287 l = &bpparser.List{} 288 } 289 l.(*bpparser.List).Values = append(l.(*bpparser.List).Values, value) 290 lists[key] = l 291 } 292 default: 293 panic(fmt.Errorf("unexpected type %t", val)) 294 } 295 296 return lists, nil 297} 298 299// classifyLocalOrGlobalPath tells whether a file path should be interpreted relative to the current module (local) 300// or relative to the root of the source checkout (global) 301func classifyLocalOrGlobalPath(value bpparser.Expression) (string, bpparser.Expression, error) { 302 switch v := value.(type) { 303 case *bpparser.Variable: 304 if v.Name == "LOCAL_PATH" { 305 return "local", &bpparser.String{ 306 Value: ".", 307 }, nil 308 } else { 309 // TODO: Should we split variables? 310 return "global", value, nil 311 } 312 case *bpparser.Operator: 313 if v.Type() != bpparser.StringType { 314 return "", nil, fmt.Errorf("classifyLocalOrGlobalPath expected a string, got %s", v.Type()) 315 } 316 317 if v.Operator != '+' { 318 return "global", value, nil 319 } 320 321 firstOperand := v.Args[0] 322 secondOperand := v.Args[1] 323 if firstOperand.Type() != bpparser.StringType { 324 return "global", value, nil 325 } 326 327 if _, ok := firstOperand.(*bpparser.Operator); ok { 328 return "global", value, nil 329 } 330 331 if variable, ok := firstOperand.(*bpparser.Variable); !ok || variable.Name != "LOCAL_PATH" { 332 return "global", value, nil 333 } 334 335 local := secondOperand 336 if s, ok := secondOperand.(*bpparser.String); ok { 337 if strings.HasPrefix(s.Value, "/") { 338 s.Value = s.Value[1:] 339 } 340 } 341 return "local", local, nil 342 case *bpparser.String: 343 return "global", value, nil 344 default: 345 return "", nil, fmt.Errorf("classifyLocalOrGlobalPath expected a string, got %s", v.Type()) 346 347 } 348} 349 350// splitAndAssign splits a Make list into components and then 351// creates the corresponding variable assignments. 352func splitAndAssign(ctx variableAssignmentContext, splitFunc listSplitFunc, namesByClassification map[string]string) error { 353 val, err := makeVariableToBlueprint(ctx.file, ctx.mkvalue, bpparser.ListType) 354 if err != nil { 355 return err 356 } 357 358 lists, err := splitBpList(val, splitFunc) 359 if err != nil { 360 return err 361 } 362 363 var classifications []string 364 for classification := range namesByClassification { 365 classifications = append(classifications, classification) 366 } 367 sort.Strings(classifications) 368 369 for _, nameClassification := range classifications { 370 name := namesByClassification[nameClassification] 371 if component, ok := lists[nameClassification]; ok && !emptyList(component) { 372 err = setVariable(ctx.file, ctx.append, ctx.prefix, name, component, true) 373 if err != nil { 374 return err 375 } 376 } 377 } 378 return nil 379} 380 381func localIncludeDirs(ctx variableAssignmentContext) error { 382 return splitAndAssign(ctx, classifyLocalOrGlobalPath, map[string]string{"global": "include_dirs", "local": "local_include_dirs"}) 383} 384 385func exportIncludeDirs(ctx variableAssignmentContext) error { 386 // Add any paths that could not be converted to local relative paths to export_include_dirs 387 // anyways, they will cause an error if they don't exist and can be fixed manually. 388 return splitAndAssign(ctx, classifyLocalOrGlobalPath, map[string]string{"global": "export_include_dirs", "local": "export_include_dirs"}) 389} 390 391func local32BitOnly(ctx variableAssignmentContext) error { 392 val, err := makeVariableToBlueprint(ctx.file, ctx.mkvalue, bpparser.BoolType) 393 if err != nil { 394 return err 395 } 396 boolValue, ok := val.(*bpparser.Bool) 397 if !ok { 398 return fmt.Errorf("value should evaluate to boolean literal") 399 } 400 if boolValue.Value { 401 thirtyTwo := &bpparser.String{ 402 Value: "32", 403 } 404 return setVariable(ctx.file, false, ctx.prefix, "compile_multilib", thirtyTwo, true) 405 } 406 return nil 407} 408 409func localAidlIncludes(ctx variableAssignmentContext) error { 410 return splitAndAssign(ctx, classifyLocalOrGlobalPath, map[string]string{"global": "aidl.include_dirs", "local": "aidl.local_include_dirs"}) 411} 412 413func localizePathList(attribute string) func(ctx variableAssignmentContext) error { 414 return func(ctx variableAssignmentContext) error { 415 paths, err := localizePaths(ctx) 416 if err == nil { 417 err = setVariable(ctx.file, ctx.append, ctx.prefix, attribute, paths, true) 418 } 419 return err 420 } 421} 422 423func localizePath(attribute string) func(ctx variableAssignmentContext) error { 424 return func(ctx variableAssignmentContext) error { 425 paths, err := localizePaths(ctx) 426 if err == nil { 427 pathList, ok := paths.(*bpparser.List) 428 if !ok { 429 panic("Expected list") 430 } 431 switch len(pathList.Values) { 432 case 0: 433 err = setVariable(ctx.file, ctx.append, ctx.prefix, attribute, &bpparser.List{}, true) 434 case 1: 435 err = setVariable(ctx.file, ctx.append, ctx.prefix, attribute, pathList.Values[0], true) 436 default: 437 err = fmt.Errorf("Expected single value for %s", attribute) 438 } 439 } 440 return err 441 } 442} 443 444// Convert the "full" paths (that is, from the top of the source tree) to the relative one 445// (from the directory containing the blueprint file) and set given attribute to it. 446// This is needed for some of makefile variables (e.g., LOCAL_RESOURCE_DIR). 447// At the moment only the paths of the `$(LOCAL_PATH)/foo/bar` format can be converted 448// (to `foo/bar` in this case) as we cannot convert a literal path without 449// knowing makefiles's location in the source tree. We just issue a warning in the latter case. 450func localizePaths(ctx variableAssignmentContext) (bpparser.Expression, error) { 451 bpvalue, err := makeVariableToBlueprint(ctx.file, ctx.mkvalue, bpparser.ListType) 452 var result bpparser.Expression 453 if err != nil { 454 return result, err 455 } 456 classifiedPaths, err := splitBpList(bpvalue, classifyLocalOrGlobalPath) 457 if err != nil { 458 return result, err 459 } 460 for pathClass, path := range classifiedPaths { 461 switch pathClass { 462 case "local": 463 result = path 464 default: 465 err = fmt.Errorf("Only $(LOCAL_PATH)/.. values are allowed") 466 } 467 } 468 return result, err 469} 470 471func stem(ctx variableAssignmentContext) error { 472 val, err := makeVariableToBlueprint(ctx.file, ctx.mkvalue, bpparser.StringType) 473 if err != nil { 474 return err 475 } 476 varName := "stem" 477 478 if exp, ok := val.(*bpparser.Operator); ok && exp.Operator == '+' { 479 if variable, ok := exp.Args[0].(*bpparser.Variable); ok && variable.Name == "LOCAL_MODULE" { 480 varName = "suffix" 481 val = exp.Args[1] 482 } 483 } 484 485 return setVariable(ctx.file, ctx.append, ctx.prefix, varName, val, true) 486} 487 488func hostOs(ctx variableAssignmentContext) error { 489 val, err := makeVariableToBlueprint(ctx.file, ctx.mkvalue, bpparser.ListType) 490 if err != nil { 491 return err 492 } 493 494 inList := func(s string) bool { 495 for _, v := range val.(*bpparser.List).Values { 496 if v.(*bpparser.String).Value == s { 497 return true 498 } 499 } 500 return false 501 } 502 503 falseValue := &bpparser.Bool{ 504 Value: false, 505 } 506 507 if inList("windows") { 508 err = setVariable(ctx.file, ctx.append, "target.windows", "enabled", trueValue, true) 509 } 510 511 if !inList("linux") && err == nil { 512 err = setVariable(ctx.file, ctx.append, "target.linux_glibc", "enabled", falseValue, true) 513 } 514 515 if !inList("darwin") && err == nil { 516 err = setVariable(ctx.file, ctx.append, "target.darwin", "enabled", falseValue, true) 517 } 518 519 return err 520} 521 522func sanitize(sub string) func(ctx variableAssignmentContext) error { 523 return func(ctx variableAssignmentContext) error { 524 val, err := makeVariableToBlueprint(ctx.file, ctx.mkvalue, bpparser.ListType) 525 if err != nil { 526 return err 527 } 528 529 if _, ok := val.(*bpparser.List); !ok { 530 return fmt.Errorf("unsupported sanitize expression") 531 } 532 533 misc := &bpparser.List{} 534 535 for _, v := range val.(*bpparser.List).Values { 536 switch v := v.(type) { 537 case *bpparser.Variable, *bpparser.Operator: 538 ctx.file.errorf(ctx.mkvalue, "unsupported sanitize expression") 539 case *bpparser.String: 540 switch v.Value { 541 case "never", "address", "fuzzer", "thread", "undefined", "cfi": 542 bpTrue := &bpparser.Bool{ 543 Value: true, 544 } 545 err = setVariable(ctx.file, false, ctx.prefix, "sanitize."+sub+v.Value, bpTrue, true) 546 if err != nil { 547 return err 548 } 549 default: 550 misc.Values = append(misc.Values, v) 551 } 552 default: 553 return fmt.Errorf("sanitize expected a string, got %s", v.Type()) 554 } 555 } 556 557 if len(misc.Values) > 0 { 558 err = setVariable(ctx.file, false, ctx.prefix, "sanitize."+sub+"misc_undefined", misc, true) 559 if err != nil { 560 return err 561 } 562 } 563 564 return err 565 } 566} 567 568func strip() func(ctx variableAssignmentContext) error { 569 return func(ctx variableAssignmentContext) error { 570 val, err := makeVariableToBlueprint(ctx.file, ctx.mkvalue, bpparser.StringType) 571 if err != nil { 572 return err 573 } 574 575 if _, ok := val.(*bpparser.String); !ok { 576 return fmt.Errorf("unsupported strip expression") 577 } 578 579 bpTrue := &bpparser.Bool{ 580 Value: true, 581 } 582 v := val.(*bpparser.String).Value 583 sub := (map[string]string{"false": "none", "true": "all", "keep_symbols": "keep_symbols"})[v] 584 if sub == "" { 585 return fmt.Errorf("unexpected strip option: %s", v) 586 } 587 return setVariable(ctx.file, false, ctx.prefix, "strip."+sub, bpTrue, true) 588 } 589} 590 591func prebuiltClass(ctx variableAssignmentContext) error { 592 class := ctx.mkvalue.Value(ctx.file.scope) 593 if _, ok := prebuiltTypes[class]; ok { 594 ctx.file.scope.Set("BUILD_PREBUILT", class) 595 } else { 596 // reset to default 597 ctx.file.scope.Set("BUILD_PREBUILT", "prebuilt") 598 } 599 return nil 600} 601 602func makeBlueprintStringAssignment(file *bpFile, prefix string, suffix string, value string) error { 603 val, err := makeVariableToBlueprint(file, mkparser.SimpleMakeString(value, mkparser.NoPos), bpparser.StringType) 604 if err == nil { 605 err = setVariable(file, false, prefix, suffix, val, true) 606 } 607 return err 608} 609 610// If variable is a literal variable name, return the name, otherwise return "" 611func varLiteralName(variable mkparser.Variable) string { 612 if len(variable.Name.Variables) == 0 { 613 return variable.Name.Strings[0] 614 } 615 return "" 616} 617 618func prebuiltModulePath(ctx variableAssignmentContext) error { 619 // Cannot handle appending 620 if ctx.append { 621 return fmt.Errorf("Cannot handle appending to LOCAL_MODULE_PATH") 622 } 623 // Analyze value in order to set the correct values for the 'device_specific', 624 // 'product_specific', 'system_ext_specific' 'vendor'/'soc_specific', 625 // 'system_ext_specific' attribute. Two cases are allowed: 626 // $(VAR)/<literal-value> 627 // $(PRODUCT_OUT)/$(TARGET_COPY_OUT_VENDOR)/<literal-value> 628 // The last case is equivalent to $(TARGET_OUT_VENDOR)/<literal-value> 629 // Map the variable name if present to `local_module_path_var` 630 // Map literal-path to local_module_path_fixed 631 varname := "" 632 fixed := "" 633 val := ctx.mkvalue 634 if len(val.Variables) == 1 && varLiteralName(val.Variables[0]) != "" && len(val.Strings) == 2 && val.Strings[0] == "" { 635 fixed = val.Strings[1] 636 varname = val.Variables[0].Name.Strings[0] 637 } else if len(val.Variables) == 2 && varLiteralName(val.Variables[0]) == "PRODUCT_OUT" && varLiteralName(val.Variables[1]) == "TARGET_COPY_OUT_VENDOR" && 638 len(val.Strings) == 3 && val.Strings[0] == "" && val.Strings[1] == "/" { 639 fixed = val.Strings[2] 640 varname = "TARGET_OUT_VENDOR" 641 } else { 642 return fmt.Errorf("LOCAL_MODULE_PATH value should start with $(<some-varaible>)/ or $(PRODUCT_OUT)/$(TARGET_COPY_VENDOR)/") 643 } 644 err := makeBlueprintStringAssignment(ctx.file, "local_module_path", "var", varname) 645 if err == nil && fixed != "" { 646 err = makeBlueprintStringAssignment(ctx.file, "local_module_path", "fixed", fixed) 647 } 648 return err 649} 650 651func ldflags(ctx variableAssignmentContext) error { 652 val, err := makeVariableToBlueprint(ctx.file, ctx.mkvalue, bpparser.ListType) 653 if err != nil { 654 return err 655 } 656 657 lists, err := splitBpList(val, func(value bpparser.Expression) (string, bpparser.Expression, error) { 658 // Anything other than "-Wl,--version_script," + LOCAL_PATH + "<path>" matches ldflags 659 exp1, ok := value.(*bpparser.Operator) 660 if !ok { 661 return "ldflags", value, nil 662 } 663 664 exp2, ok := exp1.Args[0].(*bpparser.Operator) 665 if !ok { 666 return "ldflags", value, nil 667 } 668 669 if s, ok := exp2.Args[0].(*bpparser.String); !ok || s.Value != "-Wl,--version-script," { 670 return "ldflags", value, nil 671 } 672 673 if v, ok := exp2.Args[1].(*bpparser.Variable); !ok || v.Name != "LOCAL_PATH" { 674 ctx.file.errorf(ctx.mkvalue, "Unrecognized version-script") 675 return "ldflags", value, nil 676 } 677 678 s, ok := exp1.Args[1].(*bpparser.String) 679 if !ok { 680 ctx.file.errorf(ctx.mkvalue, "Unrecognized version-script") 681 return "ldflags", value, nil 682 } 683 684 s.Value = strings.TrimPrefix(s.Value, "/") 685 686 return "version", s, nil 687 }) 688 if err != nil { 689 return err 690 } 691 692 if ldflags, ok := lists["ldflags"]; ok && !emptyList(ldflags) { 693 err = setVariable(ctx.file, ctx.append, ctx.prefix, "ldflags", ldflags, true) 694 if err != nil { 695 return err 696 } 697 } 698 699 if version_script, ok := lists["version"]; ok && !emptyList(version_script) { 700 if len(version_script.(*bpparser.List).Values) > 1 { 701 ctx.file.errorf(ctx.mkvalue, "multiple version scripts found?") 702 } 703 err = setVariable(ctx.file, false, ctx.prefix, "version_script", version_script.(*bpparser.List).Values[0], true) 704 if err != nil { 705 return err 706 } 707 } 708 709 return nil 710} 711 712func prebuiltPreprocessed(ctx variableAssignmentContext) error { 713 ctx.mkvalue = ctx.mkvalue.Clone() 714 return setVariable(ctx.file, false, ctx.prefix, "preprocessed", trueValue, true) 715} 716 717func cflags(ctx variableAssignmentContext) error { 718 // The Soong replacement for CFLAGS doesn't need the same extra escaped quotes that were present in Make 719 ctx.mkvalue = ctx.mkvalue.Clone() 720 ctx.mkvalue.ReplaceLiteral(`\"`, `"`) 721 return includeVariableNow(bpVariable{"cflags", bpparser.ListType}, ctx) 722} 723 724func proguardEnabled(ctx variableAssignmentContext) error { 725 val, err := makeVariableToBlueprint(ctx.file, ctx.mkvalue, bpparser.ListType) 726 if err != nil { 727 return err 728 } 729 730 list, ok := val.(*bpparser.List) 731 if !ok { 732 return fmt.Errorf("unsupported proguard expression") 733 } 734 735 set := func(prop string, value bool) { 736 bpValue := &bpparser.Bool{ 737 Value: value, 738 } 739 setVariable(ctx.file, false, ctx.prefix, prop, bpValue, true) 740 } 741 742 enable := false 743 744 for _, v := range list.Values { 745 s, ok := v.(*bpparser.String) 746 if !ok { 747 return fmt.Errorf("unsupported proguard expression") 748 } 749 750 switch s.Value { 751 case "disabled": 752 set("optimize.enabled", false) 753 case "obfuscation": 754 enable = true 755 set("optimize.obfuscate", true) 756 case "optimization": 757 enable = true 758 set("optimize.optimize", true) 759 case "full": 760 enable = true 761 case "custom": 762 set("optimize.no_aapt_flags", true) 763 enable = true 764 default: 765 return fmt.Errorf("unsupported proguard value %q", s) 766 } 767 } 768 769 if enable { 770 // This is only necessary for libraries which default to false, but we can't 771 // tell the difference between a library and an app here. 772 set("optimize.enabled", true) 773 } 774 775 return nil 776} 777 778func invert(name string) func(ctx variableAssignmentContext) error { 779 return func(ctx variableAssignmentContext) error { 780 val, err := makeVariableToBlueprint(ctx.file, ctx.mkvalue, bpparser.BoolType) 781 if err != nil { 782 return err 783 } 784 785 val.(*bpparser.Bool).Value = !val.(*bpparser.Bool).Value 786 787 return setVariable(ctx.file, ctx.append, ctx.prefix, name, val, true) 788 } 789} 790 791// given a conditional, returns a function that will insert a variable assignment or not, based on the conditional 792func includeVariableIf(bpVar bpVariable, conditional func(ctx variableAssignmentContext) bool) func(ctx variableAssignmentContext) error { 793 return func(ctx variableAssignmentContext) error { 794 var err error 795 if conditional(ctx) { 796 err = includeVariableNow(bpVar, ctx) 797 } 798 return err 799 } 800} 801 802// given a variable, returns a function that will always insert a variable assignment 803func includeVariable(bpVar bpVariable) func(ctx variableAssignmentContext) error { 804 return includeVariableIf(bpVar, always) 805} 806 807func includeVariableNow(bpVar bpVariable, ctx variableAssignmentContext) error { 808 var val bpparser.Expression 809 var err error 810 val, err = makeVariableToBlueprint(ctx.file, ctx.mkvalue, bpVar.variableType) 811 if err == nil { 812 err = setVariable(ctx.file, ctx.append, ctx.prefix, bpVar.name, val, true) 813 } 814 return err 815} 816 817// given a function that returns a bool, returns a function that returns the opposite 818func not(conditional func(ctx variableAssignmentContext) bool) func(ctx variableAssignmentContext) bool { 819 return func(ctx variableAssignmentContext) bool { 820 return !conditional(ctx) 821 } 822} 823 824// returns a function that tells whether mkvalue.Dump equals the given query string 825func valueDumpEquals(textToMatch string) func(ctx variableAssignmentContext) bool { 826 return func(ctx variableAssignmentContext) bool { 827 return (ctx.mkvalue.Dump() == textToMatch) 828 } 829} 830 831func always(ctx variableAssignmentContext) bool { 832 return true 833} 834 835func skip(ctx variableAssignmentContext) error { 836 return nil 837} 838 839// Shorter suffixes of other suffixes must be at the end of the list 840var propertyPrefixes = []struct{ mk, bp string }{ 841 {"arm", "arch.arm"}, 842 {"arm64", "arch.arm64"}, 843 {"x86", "arch.x86"}, 844 {"x86_64", "arch.x86_64"}, 845 {"32", "multilib.lib32"}, 846 // 64 must be after x86_64 847 {"64", "multilib.lib64"}, 848 {"darwin", "target.darwin"}, 849 {"linux", "target.linux_glibc"}, 850 {"windows", "target.windows"}, 851} 852 853var conditionalTranslations = map[string]map[bool]string{ 854 "($(HOST_OS),darwin)": { 855 true: "target.darwin", 856 false: "target.not_darwin"}, 857 "($(HOST_OS), darwin)": { 858 true: "target.darwin", 859 false: "target.not_darwin"}, 860 "($(HOST_OS),windows)": { 861 true: "target.windows", 862 false: "target.not_windows"}, 863 "($(HOST_OS), windows)": { 864 true: "target.windows", 865 false: "target.not_windows"}, 866 "($(HOST_OS),linux)": { 867 true: "target.linux_glibc", 868 false: "target.not_linux_glibc"}, 869 "($(HOST_OS), linux)": { 870 true: "target.linux_glibc", 871 false: "target.not_linux_glibc"}, 872 "($(BUILD_OS),darwin)": { 873 true: "target.darwin", 874 false: "target.not_darwin"}, 875 "($(BUILD_OS), darwin)": { 876 true: "target.darwin", 877 false: "target.not_darwin"}, 878 "($(BUILD_OS),linux)": { 879 true: "target.linux_glibc", 880 false: "target.not_linux_glibc"}, 881 "($(BUILD_OS), linux)": { 882 true: "target.linux_glibc", 883 false: "target.not_linux_glibc"}, 884 "(,$(TARGET_BUILD_APPS))": { 885 false: "product_variables.unbundled_build"}, 886 "($(TARGET_BUILD_APPS),)": { 887 false: "product_variables.unbundled_build"}, 888 "($(TARGET_BUILD_PDK),true)": { 889 true: "product_variables.pdk"}, 890 "($(TARGET_BUILD_PDK), true)": { 891 true: "product_variables.pdk"}, 892} 893 894func mydir(args []string) []string { 895 return []string{"."} 896} 897 898func allFilesUnder(wildcard string) func(args []string) []string { 899 return func(args []string) []string { 900 dirs := []string{""} 901 if len(args) > 0 { 902 dirs = strings.Fields(args[0]) 903 } 904 905 paths := make([]string, len(dirs)) 906 for i := range paths { 907 paths[i] = fmt.Sprintf("%s/**/"+wildcard, dirs[i]) 908 } 909 return paths 910 } 911} 912 913func allSubdirJavaFiles(args []string) []string { 914 return []string{"**/*.java"} 915} 916 917func includeIgnored(args []string) []string { 918 return []string{includeIgnoredPath} 919} 920 921var moduleTypes = map[string]string{ 922 "BUILD_SHARED_LIBRARY": "cc_library_shared", 923 "BUILD_STATIC_LIBRARY": "cc_library_static", 924 "BUILD_HOST_SHARED_LIBRARY": "cc_library_host_shared", 925 "BUILD_HOST_STATIC_LIBRARY": "cc_library_host_static", 926 "BUILD_HEADER_LIBRARY": "cc_library_headers", 927 "BUILD_EXECUTABLE": "cc_binary", 928 "BUILD_HOST_EXECUTABLE": "cc_binary_host", 929 "BUILD_NATIVE_TEST": "cc_test", 930 "BUILD_HOST_NATIVE_TEST": "cc_test_host", 931 "BUILD_NATIVE_BENCHMARK": "cc_benchmark", 932 "BUILD_HOST_NATIVE_BENCHMARK": "cc_benchmark_host", 933 934 "BUILD_JAVA_LIBRARY": "java_library_installable", // will be rewritten to java_library by bpfix 935 "BUILD_STATIC_JAVA_LIBRARY": "java_library", 936 "BUILD_HOST_JAVA_LIBRARY": "java_library_host", 937 "BUILD_HOST_DALVIK_JAVA_LIBRARY": "java_library_host_dalvik", 938 "BUILD_PACKAGE": "android_app", 939 "BUILD_RRO_PACKAGE": "runtime_resource_overlay", 940 941 "BUILD_CTS_EXECUTABLE": "cc_binary", // will be further massaged by bpfix depending on the output path 942 "BUILD_CTS_SUPPORT_PACKAGE": "cts_support_package", // will be rewritten to android_test by bpfix 943 "BUILD_CTS_PACKAGE": "cts_package", // will be rewritten to android_test by bpfix 944 "BUILD_CTS_TARGET_JAVA_LIBRARY": "cts_target_java_library", // will be rewritten to java_library by bpfix 945 "BUILD_CTS_HOST_JAVA_LIBRARY": "cts_host_java_library", // will be rewritten to java_library_host by bpfix 946} 947 948var prebuiltTypes = map[string]string{ 949 "SHARED_LIBRARIES": "cc_prebuilt_library_shared", 950 "STATIC_LIBRARIES": "cc_prebuilt_library_static", 951 "EXECUTABLES": "cc_prebuilt_binary", 952 "JAVA_LIBRARIES": "java_import", 953 "APPS": "android_app_import", 954 "ETC": "prebuilt_etc", 955} 956 957var soongModuleTypes = map[string]bool{} 958 959var includePathToModule = map[string]string{ 960 // The content will be populated dynamically in androidScope below 961} 962 963func mapIncludePath(path string) (string, bool) { 964 if path == clearVarsPath || path == includeIgnoredPath { 965 return path, true 966 } 967 module, ok := includePathToModule[path] 968 return module, ok 969} 970 971func androidScope() mkparser.Scope { 972 globalScope := mkparser.NewScope(nil) 973 globalScope.Set("CLEAR_VARS", clearVarsPath) 974 globalScope.SetFunc("my-dir", mydir) 975 globalScope.SetFunc("all-java-files-under", allFilesUnder("*.java")) 976 globalScope.SetFunc("all-proto-files-under", allFilesUnder("*.proto")) 977 globalScope.SetFunc("all-aidl-files-under", allFilesUnder("*.aidl")) 978 globalScope.SetFunc("all-Iaidl-files-under", allFilesUnder("I*.aidl")) 979 globalScope.SetFunc("all-logtags-files-under", allFilesUnder("*.logtags")) 980 globalScope.SetFunc("all-subdir-java-files", allSubdirJavaFiles) 981 globalScope.SetFunc("all-makefiles-under", includeIgnored) 982 globalScope.SetFunc("first-makefiles-under", includeIgnored) 983 globalScope.SetFunc("all-named-subdir-makefiles", includeIgnored) 984 globalScope.SetFunc("all-subdir-makefiles", includeIgnored) 985 986 // The scope maps each known variable to a path, and then includePathToModule maps a path 987 // to a module. We don't care what the actual path value is so long as the value in scope 988 // is mapped, so we might as well use variable name as key, too. 989 for varName, moduleName := range moduleTypes { 990 path := varName 991 globalScope.Set(varName, path) 992 includePathToModule[path] = moduleName 993 } 994 for varName, moduleName := range prebuiltTypes { 995 includePathToModule[varName] = moduleName 996 } 997 998 return globalScope 999} 1000