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