|  | // Copyright 2016 Google Inc. All rights reserved. | 
|  | // | 
|  | // Licensed under the Apache License, Version 2.0 (the "License"); | 
|  | // you may not use this file except in compliance with the License. | 
|  | // You may obtain a copy of the License at | 
|  | // | 
|  | //     http://www.apache.org/licenses/LICENSE-2.0 | 
|  | // | 
|  | // Unless required by applicable law or agreed to in writing, software | 
|  | // distributed under the License is distributed on an "AS IS" BASIS, | 
|  | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
|  | // See the License for the specific language governing permissions and | 
|  | // limitations under the License. | 
|  |  | 
|  | package cc | 
|  |  | 
|  | import ( | 
|  | "fmt" | 
|  | "sort" | 
|  | "strings" | 
|  | "sync" | 
|  |  | 
|  | "android/soong/android" | 
|  | "android/soong/cc/config" | 
|  | ) | 
|  |  | 
|  | var ( | 
|  | modulesAddedWallKey          = android.NewOnceKey("ModulesAddedWall") | 
|  | modulesUsingWnoErrorKey      = android.NewOnceKey("ModulesUsingWnoError") | 
|  | modulesMissingProfileFileKey = android.NewOnceKey("ModulesMissingProfileFile") | 
|  | ) | 
|  |  | 
|  | func init() { | 
|  | android.RegisterMakeVarsProvider(pctx, makeVarsProvider) | 
|  | } | 
|  |  | 
|  | func getNamedMapForConfig(config android.Config, key android.OnceKey) *sync.Map { | 
|  | return config.Once(key, func() interface{} { | 
|  | return &sync.Map{} | 
|  | }).(*sync.Map) | 
|  | } | 
|  |  | 
|  | func makeStringOfKeys(ctx android.MakeVarsContext, key android.OnceKey) string { | 
|  | set := getNamedMapForConfig(ctx.Config(), key) | 
|  | keys := []string{} | 
|  | set.Range(func(key interface{}, value interface{}) bool { | 
|  | keys = append(keys, key.(string)) | 
|  | return true | 
|  | }) | 
|  | sort.Strings(keys) | 
|  | return strings.Join(keys, " ") | 
|  | } | 
|  |  | 
|  | func makeStringOfWarningAllowedProjects() string { | 
|  | allProjects := append([]string{}, config.WarningAllowedProjects...) | 
|  | allProjects = append(allProjects, config.WarningAllowedOldProjects...) | 
|  | sort.Strings(allProjects) | 
|  | // Makefile rules use pattern "path/%" to match module paths. | 
|  | if len(allProjects) > 0 { | 
|  | return strings.Join(allProjects, "% ") + "%" | 
|  | } else { | 
|  | return "" | 
|  | } | 
|  | } | 
|  |  | 
|  | type notOnHostContext struct { | 
|  | } | 
|  |  | 
|  | func (c *notOnHostContext) Host() bool { | 
|  | return false | 
|  | } | 
|  |  | 
|  | func makeVarsProvider(ctx android.MakeVarsContext) { | 
|  | vendorPublicLibraries := vendorPublicLibraries(ctx.Config()) | 
|  |  | 
|  | ctx.Strict("LLVM_RELEASE_VERSION", "${config.ClangShortVersion}") | 
|  | ctx.Strict("LLVM_PREBUILTS_VERSION", "${config.ClangVersion}") | 
|  | ctx.Strict("LLVM_PREBUILTS_BASE", "${config.ClangBase}") | 
|  | ctx.Strict("LLVM_PREBUILTS_PATH", "${config.ClangBin}") | 
|  | ctx.Strict("CLANG", "${config.ClangBin}/clang") | 
|  | ctx.Strict("CLANG_CXX", "${config.ClangBin}/clang++") | 
|  | ctx.Strict("LLVM_AS", "${config.ClangBin}/llvm-as") | 
|  | ctx.Strict("LLVM_LINK", "${config.ClangBin}/llvm-link") | 
|  | ctx.Strict("LLVM_OBJCOPY", "${config.ClangBin}/llvm-objcopy") | 
|  | ctx.Strict("LLVM_STRIP", "${config.ClangBin}/llvm-strip") | 
|  | ctx.Strict("PATH_TO_CLANG_TIDY", "${config.ClangBin}/clang-tidy") | 
|  | ctx.StrictSorted("CLANG_CONFIG_UNKNOWN_CFLAGS", strings.Join(config.ClangUnknownCflags, " ")) | 
|  |  | 
|  | ctx.Strict("RS_LLVM_PREBUILTS_VERSION", "${config.RSClangVersion}") | 
|  | ctx.Strict("RS_LLVM_PREBUILTS_BASE", "${config.RSClangBase}") | 
|  | ctx.Strict("RS_LLVM_PREBUILTS_PATH", "${config.RSLLVMPrebuiltsPath}") | 
|  | ctx.Strict("RS_LLVM_INCLUDES", "${config.RSIncludePath}") | 
|  | ctx.Strict("RS_CLANG", "${config.RSLLVMPrebuiltsPath}/clang") | 
|  | ctx.Strict("RS_LLVM_AS", "${config.RSLLVMPrebuiltsPath}/llvm-as") | 
|  | ctx.Strict("RS_LLVM_LINK", "${config.RSLLVMPrebuiltsPath}/llvm-link") | 
|  |  | 
|  | ctx.Strict("CLANG_EXTERNAL_CFLAGS", "${config.ClangExternalCflags}") | 
|  | ctx.Strict("GLOBAL_CLANG_CFLAGS_NO_OVERRIDE", "${config.NoOverrideClangGlobalCflags}") | 
|  | ctx.Strict("GLOBAL_CLANG_CPPFLAGS_NO_OVERRIDE", "") | 
|  |  | 
|  | ctx.Strict("BOARD_VNDK_VERSION", ctx.DeviceConfig().VndkVersion()) | 
|  |  | 
|  | // Filter vendor_public_library that are exported to make | 
|  | exportedVendorPublicLibraries := []string{} | 
|  | ctx.VisitAllModules(func(module android.Module) { | 
|  | if ccModule, ok := module.(*Module); ok { | 
|  | baseName := ccModule.BaseModuleName() | 
|  | if inList(baseName, *vendorPublicLibraries) && module.ExportedToMake() { | 
|  | if !inList(baseName, exportedVendorPublicLibraries) { | 
|  | exportedVendorPublicLibraries = append(exportedVendorPublicLibraries, baseName) | 
|  | } | 
|  | } | 
|  | } | 
|  | }) | 
|  | sort.Strings(exportedVendorPublicLibraries) | 
|  | ctx.Strict("VENDOR_PUBLIC_LIBRARIES", strings.Join(exportedVendorPublicLibraries, " ")) | 
|  |  | 
|  | sort.Strings(lsdumpPaths) | 
|  | ctx.Strict("LSDUMP_PATHS", strings.Join(lsdumpPaths, " ")) | 
|  |  | 
|  | ctx.Strict("ANDROID_WARNING_ALLOWED_PROJECTS", makeStringOfWarningAllowedProjects()) | 
|  | ctx.Strict("SOONG_MODULES_ADDED_WALL", makeStringOfKeys(ctx, modulesAddedWallKey)) | 
|  | ctx.Strict("SOONG_MODULES_USING_WNO_ERROR", makeStringOfKeys(ctx, modulesUsingWnoErrorKey)) | 
|  | ctx.Strict("SOONG_MODULES_MISSING_PGO_PROFILE_FILE", makeStringOfKeys(ctx, modulesMissingProfileFileKey)) | 
|  |  | 
|  | ctx.Strict("ADDRESS_SANITIZER_CONFIG_EXTRA_CFLAGS", strings.Join(asanCflags, " ")) | 
|  | ctx.Strict("ADDRESS_SANITIZER_CONFIG_EXTRA_LDFLAGS", strings.Join(asanLdflags, " ")) | 
|  |  | 
|  | ctx.Strict("HWADDRESS_SANITIZER_CONFIG_EXTRA_CFLAGS", strings.Join(hwasanCflags, " ")) | 
|  | ctx.Strict("HWADDRESS_SANITIZER_GLOBAL_OPTIONS", strings.Join(hwasanGlobalOptions, ",")) | 
|  |  | 
|  | ctx.Strict("CFI_EXTRA_CFLAGS", strings.Join(cfiCflags, " ")) | 
|  | ctx.Strict("CFI_EXTRA_ASFLAGS", strings.Join(cfiAsflags, " ")) | 
|  | ctx.Strict("CFI_EXTRA_LDFLAGS", strings.Join(cfiLdflags, " ")) | 
|  |  | 
|  | ctx.Strict("INTEGER_OVERFLOW_EXTRA_CFLAGS", strings.Join(intOverflowCflags, " ")) | 
|  |  | 
|  | ctx.Strict("DEFAULT_C_STD_VERSION", config.CStdVersion) | 
|  | ctx.Strict("DEFAULT_CPP_STD_VERSION", config.CppStdVersion) | 
|  | ctx.Strict("EXPERIMENTAL_C_STD_VERSION", config.ExperimentalCStdVersion) | 
|  | ctx.Strict("EXPERIMENTAL_CPP_STD_VERSION", config.ExperimentalCppStdVersion) | 
|  |  | 
|  | ctx.Strict("DEFAULT_GLOBAL_TIDY_CHECKS", "${config.TidyDefaultGlobalChecks}") | 
|  | ctx.Strict("DEFAULT_LOCAL_TIDY_CHECKS", joinLocalTidyChecks(config.DefaultLocalTidyChecks)) | 
|  | ctx.Strict("DEFAULT_TIDY_HEADER_DIRS", "${config.TidyDefaultHeaderDirs}") | 
|  | ctx.Strict("WITH_TIDY_FLAGS", "${config.TidyWithTidyFlags}") | 
|  |  | 
|  | ctx.Strict("AIDL_CPP", "${aidlCmd}") | 
|  | ctx.Strict("ALLOWED_MANUAL_INTERFACE_PATHS", strings.Join(allowedManualInterfacePaths, " ")) | 
|  |  | 
|  | ctx.Strict("RS_GLOBAL_INCLUDES", "${config.RsGlobalIncludes}") | 
|  |  | 
|  | ctx.Strict("SOONG_STRIP_PATH", "${stripPath}") | 
|  | ctx.Strict("XZ", "${xzCmd}") | 
|  |  | 
|  | nativeHelperIncludeFlags, err := ctx.Eval("${config.CommonNativehelperInclude}") | 
|  | if err != nil { | 
|  | panic(err) | 
|  | } | 
|  | nativeHelperIncludes, nativeHelperSystemIncludes := splitSystemIncludes(ctx, nativeHelperIncludeFlags) | 
|  | if len(nativeHelperSystemIncludes) > 0 { | 
|  | panic("native helper may not have any system includes") | 
|  | } | 
|  | ctx.Strict("JNI_H_INCLUDE", strings.Join(nativeHelperIncludes, " ")) | 
|  |  | 
|  | includeFlags, err := ctx.Eval("${config.CommonGlobalIncludes}") | 
|  | if err != nil { | 
|  | panic(err) | 
|  | } | 
|  | includes, systemIncludes := splitSystemIncludes(ctx, includeFlags) | 
|  | ctx.StrictRaw("SRC_HEADERS", strings.Join(includes, " ")) | 
|  | ctx.StrictRaw("SRC_SYSTEM_HEADERS", strings.Join(systemIncludes, " ")) | 
|  |  | 
|  | sort.Strings(ndkKnownLibs) | 
|  | ctx.Strict("NDK_KNOWN_LIBS", strings.Join(ndkKnownLibs, " ")) | 
|  |  | 
|  | hostTargets := ctx.Config().Targets[android.BuildOs] | 
|  | makeVarsToolchain(ctx, "", hostTargets[0]) | 
|  | if len(hostTargets) > 1 { | 
|  | makeVarsToolchain(ctx, "2ND_", hostTargets[1]) | 
|  | } | 
|  |  | 
|  | deviceTargets := ctx.Config().Targets[android.Android] | 
|  | makeVarsToolchain(ctx, "", deviceTargets[0]) | 
|  | if len(deviceTargets) > 1 { | 
|  | makeVarsToolchain(ctx, "2ND_", deviceTargets[1]) | 
|  | } | 
|  | } | 
|  |  | 
|  | func makeVarsToolchain(ctx android.MakeVarsContext, secondPrefix string, | 
|  | target android.Target) { | 
|  | var typePrefix string | 
|  | switch target.Os.Class { | 
|  | case android.Host: | 
|  | typePrefix = "HOST_" | 
|  | case android.Device: | 
|  | typePrefix = "TARGET_" | 
|  | } | 
|  | makePrefix := secondPrefix + typePrefix | 
|  |  | 
|  | toolchain := config.FindToolchain(target.Os, target.Arch) | 
|  |  | 
|  | var productExtraCflags string | 
|  | var productExtraLdflags string | 
|  |  | 
|  | hod := "Host" | 
|  | if target.Os.Class == android.Device { | 
|  | hod = "Device" | 
|  | } | 
|  |  | 
|  | if target.Os.Class == android.Host && ctx.Config().HostStaticBinaries() { | 
|  | productExtraLdflags += "-static" | 
|  | } | 
|  |  | 
|  | includeFlags, err := ctx.Eval(toolchain.IncludeFlags()) | 
|  | if err != nil { | 
|  | panic(err) | 
|  | } | 
|  | includes, systemIncludes := splitSystemIncludes(ctx, includeFlags) | 
|  | ctx.StrictRaw(makePrefix+"C_INCLUDES", strings.Join(includes, " ")) | 
|  | ctx.StrictRaw(makePrefix+"C_SYSTEM_INCLUDES", strings.Join(systemIncludes, " ")) | 
|  |  | 
|  | if target.Arch.ArchType == android.Arm { | 
|  | flags, err := toolchain.ClangInstructionSetFlags("arm") | 
|  | if err != nil { | 
|  | panic(err) | 
|  | } | 
|  | ctx.Strict(makePrefix+"arm_CFLAGS", flags) | 
|  |  | 
|  | flags, err = toolchain.ClangInstructionSetFlags("thumb") | 
|  | if err != nil { | 
|  | panic(err) | 
|  | } | 
|  | ctx.Strict(makePrefix+"thumb_CFLAGS", flags) | 
|  | } | 
|  |  | 
|  | clangPrefix := secondPrefix + "CLANG_" + typePrefix | 
|  | clangExtras := "-B" + config.ToolPath(toolchain) | 
|  |  | 
|  | ctx.Strict(clangPrefix+"TRIPLE", toolchain.ClangTriple()) | 
|  | ctx.Strict(clangPrefix+"GLOBAL_CFLAGS", strings.Join([]string{ | 
|  | toolchain.ClangCflags(), | 
|  | "${config.CommonClangGlobalCflags}", | 
|  | fmt.Sprintf("${config.%sClangGlobalCflags}", hod), | 
|  | toolchain.ToolchainClangCflags(), | 
|  | clangExtras, | 
|  | productExtraCflags, | 
|  | }, " ")) | 
|  | ctx.Strict(clangPrefix+"GLOBAL_CPPFLAGS", strings.Join([]string{ | 
|  | "${config.CommonClangGlobalCppflags}", | 
|  | fmt.Sprintf("${config.%sGlobalCppflags}", hod), | 
|  | toolchain.ClangCppflags(), | 
|  | }, " ")) | 
|  | ctx.Strict(clangPrefix+"GLOBAL_LDFLAGS", strings.Join([]string{ | 
|  | fmt.Sprintf("${config.%sGlobalLdflags}", hod), | 
|  | toolchain.ClangLdflags(), | 
|  | toolchain.ToolchainClangLdflags(), | 
|  | productExtraLdflags, | 
|  | clangExtras, | 
|  | }, " ")) | 
|  | ctx.Strict(clangPrefix+"GLOBAL_LLDFLAGS", strings.Join([]string{ | 
|  | fmt.Sprintf("${config.%sGlobalLldflags}", hod), | 
|  | toolchain.ClangLldflags(), | 
|  | toolchain.ToolchainClangLdflags(), | 
|  | productExtraLdflags, | 
|  | clangExtras, | 
|  | }, " ")) | 
|  |  | 
|  | if target.Os.Class == android.Device { | 
|  | ctx.Strict(secondPrefix+"ADDRESS_SANITIZER_RUNTIME_LIBRARY", strings.TrimSuffix(config.AddressSanitizerRuntimeLibrary(toolchain), ".so")) | 
|  | ctx.Strict(secondPrefix+"HWADDRESS_SANITIZER_RUNTIME_LIBRARY", strings.TrimSuffix(config.HWAddressSanitizerRuntimeLibrary(toolchain), ".so")) | 
|  | ctx.Strict(secondPrefix+"HWADDRESS_SANITIZER_STATIC_LIBRARY", strings.TrimSuffix(config.HWAddressSanitizerStaticLibrary(toolchain), ".a")) | 
|  | ctx.Strict(secondPrefix+"UBSAN_RUNTIME_LIBRARY", strings.TrimSuffix(config.UndefinedBehaviorSanitizerRuntimeLibrary(toolchain), ".so")) | 
|  | ctx.Strict(secondPrefix+"UBSAN_MINIMAL_RUNTIME_LIBRARY", strings.TrimSuffix(config.UndefinedBehaviorSanitizerMinimalRuntimeLibrary(toolchain), ".a")) | 
|  | ctx.Strict(secondPrefix+"TSAN_RUNTIME_LIBRARY", strings.TrimSuffix(config.ThreadSanitizerRuntimeLibrary(toolchain), ".so")) | 
|  | ctx.Strict(secondPrefix+"SCUDO_RUNTIME_LIBRARY", strings.TrimSuffix(config.ScudoRuntimeLibrary(toolchain), ".so")) | 
|  | ctx.Strict(secondPrefix+"SCUDO_MINIMAL_RUNTIME_LIBRARY", strings.TrimSuffix(config.ScudoMinimalRuntimeLibrary(toolchain), ".so")) | 
|  | } | 
|  |  | 
|  | // This is used by external/gentoo/... | 
|  | ctx.Strict("CLANG_CONFIG_"+target.Arch.ArchType.Name+"_"+typePrefix+"TRIPLE", | 
|  | toolchain.ClangTriple()) | 
|  |  | 
|  | if target.Os == android.Darwin { | 
|  | ctx.Strict(makePrefix+"AR", "${config.MacArPath}") | 
|  | ctx.Strict(makePrefix+"NM", "${config.MacToolPath}/nm") | 
|  | ctx.Strict(makePrefix+"OTOOL", "${config.MacToolPath}/otool") | 
|  | ctx.Strict(makePrefix+"STRIP", "${config.MacStripPath}") | 
|  | } else { | 
|  | ctx.Strict(makePrefix+"AR", "${config.ClangBin}/llvm-ar") | 
|  | ctx.Strict(makePrefix+"READELF", gccCmd(toolchain, "readelf")) | 
|  | ctx.Strict(makePrefix+"NM", gccCmd(toolchain, "nm")) | 
|  | ctx.Strict(makePrefix+"STRIP", gccCmd(toolchain, "strip")) | 
|  | } | 
|  |  | 
|  | if target.Os.Class == android.Device { | 
|  | ctx.Strict(makePrefix+"OBJCOPY", gccCmd(toolchain, "objcopy")) | 
|  | ctx.Strict(makePrefix+"LD", gccCmd(toolchain, "ld")) | 
|  | ctx.Strict(makePrefix+"GCC_VERSION", toolchain.GccVersion()) | 
|  | ctx.Strict(makePrefix+"NDK_TRIPLE", config.NDKTriple(toolchain)) | 
|  | ctx.Strict(makePrefix+"TOOLS_PREFIX", gccCmd(toolchain, "")) | 
|  | } | 
|  |  | 
|  | if target.Os.Class == android.Host { | 
|  | ctx.Strict(makePrefix+"AVAILABLE_LIBRARIES", strings.Join(toolchain.AvailableLibraries(), " ")) | 
|  | } | 
|  |  | 
|  | ctx.Strict(makePrefix+"SHLIB_SUFFIX", toolchain.ShlibSuffix()) | 
|  | ctx.Strict(makePrefix+"EXECUTABLE_SUFFIX", toolchain.ExecutableSuffix()) | 
|  | } | 
|  |  | 
|  | func splitSystemIncludes(ctx android.MakeVarsContext, val string) (includes, systemIncludes []string) { | 
|  | flags, err := ctx.Eval(val) | 
|  | if err != nil { | 
|  | panic(err) | 
|  | } | 
|  |  | 
|  | extract := func(flags string, dirs []string, prefix string) (string, []string, bool) { | 
|  | if strings.HasPrefix(flags, prefix) { | 
|  | flags = strings.TrimPrefix(flags, prefix) | 
|  | flags = strings.TrimLeft(flags, " ") | 
|  | s := strings.SplitN(flags, " ", 2) | 
|  | dirs = append(dirs, s[0]) | 
|  | if len(s) > 1 { | 
|  | return strings.TrimLeft(s[1], " "), dirs, true | 
|  | } | 
|  | return "", dirs, true | 
|  | } else { | 
|  | return flags, dirs, false | 
|  | } | 
|  | } | 
|  |  | 
|  | flags = strings.TrimLeft(flags, " ") | 
|  | for flags != "" { | 
|  | found := false | 
|  | flags, includes, found = extract(flags, includes, "-I") | 
|  | if !found { | 
|  | flags, systemIncludes, found = extract(flags, systemIncludes, "-isystem ") | 
|  | } | 
|  | if !found { | 
|  | panic(fmt.Errorf("Unexpected flag in %q", flags)) | 
|  | } | 
|  | } | 
|  |  | 
|  | return includes, systemIncludes | 
|  | } | 
|  |  | 
|  | func joinLocalTidyChecks(checks []config.PathBasedTidyCheck) string { | 
|  | rets := make([]string, len(checks)) | 
|  | for i, check := range config.DefaultLocalTidyChecks { | 
|  | rets[i] = check.PathPrefix + ":" + check.Checks | 
|  | } | 
|  | return strings.Join(rets, " ") | 
|  | } |