Merge "Add pom2bp"
diff --git a/Android.bp b/Android.bp
index 5396664..aa65209 100644
--- a/Android.bp
+++ b/Android.bp
@@ -145,6 +145,7 @@
"cc/vndk_prebuilt.go",
"cc/cmakelists.go",
+ "cc/compdb.go",
"cc/compiler.go",
"cc/installer.go",
"cc/linker.go",
diff --git a/README.md b/README.md
index b234c71..b3239e9 100644
--- a/README.md
+++ b/README.md
@@ -175,6 +175,7 @@
* [Best Practices](docs/best_practices.md)
* [Build Performance](docs/perf.md)
* [Generating CLion Projects](docs/clion.md)
+* [Generating YouCompleteMe/VSCode compile\_commands.json file](docs/compdb.md)
* Make-specific documentation: [build/make/README.md](https://android.googlesource.com/platform/build/+/master/README.md)
## FAQ
diff --git a/cc/cc.go b/cc/cc.go
index 1e313c0..9722cf0 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -40,7 +40,6 @@
ctx.BottomUp("ndk_api", ndkApiMutator).Parallel()
ctx.BottomUp("test_per_src", testPerSrcMutator).Parallel()
ctx.BottomUp("begin", beginMutator).Parallel()
- ctx.BottomUp("coverage", coverageLinkingMutator).Parallel()
})
android.PostDepsMutators(func(ctx android.RegisterMutatorsContext) {
@@ -55,6 +54,7 @@
ctx.TopDown("sanitize_runtime_deps", sanitizerRuntimeDepsMutator())
+ ctx.BottomUp("coverage", coverageLinkingMutator).Parallel()
ctx.TopDown("vndk_deps", sabiDepsMutator)
ctx.TopDown("lto_deps", ltoDepsMutator)
@@ -809,15 +809,12 @@
if c.compiler != nil {
deps = c.compiler.compilerDeps(ctx, deps)
}
- // clang_rt.profile runtime libraries necessary for PGO and coverage
- // depend on symbols from libgcc. Add the runtime library dependency
- // before libgcc gets added in linkerDeps().
+ // Add the PGO dependency (the clang_rt.profile runtime library), which
+ // sometimes depends on symbols from libgcc, before libgcc gets added
+ // in linkerDeps().
if c.pgo != nil {
deps = c.pgo.deps(ctx, deps)
}
- if c.coverage != nil {
- deps = c.coverage.deps(ctx, deps)
- }
if c.linker != nil {
deps = c.linker.linkerDeps(ctx, deps)
}
@@ -827,6 +824,9 @@
if c.sanitize != nil {
deps = c.sanitize.deps(ctx, deps)
}
+ if c.coverage != nil {
+ deps = c.coverage.deps(ctx, deps)
+ }
if c.sabi != nil {
deps = c.sabi.deps(ctx, deps)
}
diff --git a/cc/compdb.go b/cc/compdb.go
new file mode 100644
index 0000000..a9c5b5e
--- /dev/null
+++ b/cc/compdb.go
@@ -0,0 +1,192 @@
+// Copyright 2018 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 (
+ "encoding/json"
+ "log"
+ "os"
+ "path/filepath"
+ "strings"
+
+ "android/soong/android"
+)
+
+// This singleton generates a compile_commands.json file. It does so for each
+// blueprint Android.bp resulting in a cc.Module when either make, mm, mma, mmm
+// or mmma is called. It will only create a single compile_commands.json file
+// at out/development/ide/compdb/compile_commands.json. It will also symlink it
+// to ${SOONG_LINK_COMPDB_TO} if set. In general this should be created by running
+// make SOONG_GEN_COMPDB=1 nothing to get all targets.
+
+func init() {
+ android.RegisterSingletonType("compdb_generator", compDBGeneratorSingleton)
+}
+
+func compDBGeneratorSingleton() android.Singleton {
+ return &compdbGeneratorSingleton{}
+}
+
+type compdbGeneratorSingleton struct{}
+
+const (
+ compdbFilename = "compile_commands.json"
+ compdbOutputProjectsDirectory = "out/development/ide/compdb"
+
+ // Environment variables used to modify behavior of this singleton.
+ envVariableGenerateCompdb = "SOONG_GEN_COMPDB"
+ envVariableGenerateCompdbDebugInfo = "SOONG_GEN_COMPDB_DEBUG"
+ envVariableCompdbLink = "SOONG_LINK_COMPDB_TO"
+)
+
+// A compdb entry. The compile_commands.json file is a list of these.
+type compDbEntry struct {
+ Directory string `json:"directory"`
+ Arguments []string `json:"arguments"`
+ File string `json:"file"`
+ Output string `json:"output,omitempty"`
+}
+
+func (c *compdbGeneratorSingleton) GenerateBuildActions(ctx android.SingletonContext) {
+ if !ctx.Config().IsEnvTrue(envVariableGenerateCompdb) {
+ return
+ }
+
+ // Instruct the generator to indent the json file for easier debugging.
+ outputCompdbDebugInfo := ctx.Config().IsEnvTrue(envVariableGenerateCompdbDebugInfo)
+
+ // We only want one entry per file. We don't care what module/isa it's from
+ m := make(map[string]compDbEntry)
+ ctx.VisitAllModules(func(module android.Module) {
+ if ccModule, ok := module.(*Module); ok {
+ if compiledModule, ok := ccModule.compiler.(CompiledInterface); ok {
+ generateCompdbProject(compiledModule, ctx, ccModule, m)
+ }
+ }
+ })
+
+ // Create the output file.
+ dir := filepath.Join(getCompdbAndroidSrcRootDirectory(ctx), compdbOutputProjectsDirectory)
+ os.MkdirAll(dir, 0777)
+ compDBFile := filepath.Join(dir, compdbFilename)
+ f, err := os.Create(compdbFilename)
+ if err != nil {
+ log.Fatalf("Could not create file %s: %s", filepath.Join(dir, compdbFilename), err)
+ }
+ defer f.Close()
+
+ v := make([]compDbEntry, 0, len(m))
+
+ for _, value := range m {
+ v = append(v, value)
+ }
+ var dat []byte
+ if outputCompdbDebugInfo {
+ dat, err = json.MarshalIndent(v, "", " ")
+ } else {
+ dat, err = json.Marshal(v)
+ }
+ if err != nil {
+ log.Fatalf("Failed to marshal: %s", err)
+ }
+ f.Write(dat)
+
+ finalLinkPath := filepath.Join(ctx.Config().Getenv(envVariableCompdbLink), compdbFilename)
+ if finalLinkPath != "" {
+ os.Remove(finalLinkPath)
+ if err := os.Symlink(compDBFile, finalLinkPath); err != nil {
+ log.Fatalf("Unable to symlink %s to %s: %s", compDBFile, finalLinkPath, err)
+ }
+ }
+}
+
+func expandAllVars(ctx android.SingletonContext, args []string) []string {
+ var out []string
+ for _, arg := range args {
+ if arg != "" {
+ if val, err := evalAndSplitVariable(ctx, arg); err == nil {
+ out = append(out, val...)
+ } else {
+ out = append(out, arg)
+ }
+ }
+ }
+ return out
+}
+
+func getArguments(src android.Path, ctx android.SingletonContext, ccModule *Module) []string {
+ var args []string
+ isCpp := false
+ isAsm := false
+ // TODO It would be better to ask soong for the types here.
+ switch src.Ext() {
+ case ".S", ".s", ".asm":
+ isAsm = true
+ isCpp = false
+ case ".c":
+ isAsm = false
+ isCpp = false
+ case ".cpp", ".cc", ".mm":
+ isAsm = false
+ isCpp = true
+ default:
+ log.Print("Unknown file extension " + src.Ext() + " on file " + src.String())
+ isAsm = true
+ isCpp = false
+ }
+ // The executable for the compilation doesn't matter but we need something there.
+ args = append(args, "/bin/false")
+ args = append(args, expandAllVars(ctx, ccModule.flags.GlobalFlags)...)
+ args = append(args, expandAllVars(ctx, ccModule.flags.CFlags)...)
+ if isCpp {
+ args = append(args, expandAllVars(ctx, ccModule.flags.CppFlags)...)
+ } else if !isAsm {
+ args = append(args, expandAllVars(ctx, ccModule.flags.ConlyFlags)...)
+ }
+ args = append(args, expandAllVars(ctx, ccModule.flags.SystemIncludeFlags)...)
+ args = append(args, src.String())
+ return args
+}
+
+func generateCompdbProject(compiledModule CompiledInterface, ctx android.SingletonContext, ccModule *Module, builds map[string]compDbEntry) {
+ srcs := compiledModule.Srcs()
+ if len(srcs) == 0 {
+ return
+ }
+
+ rootDir := getCompdbAndroidSrcRootDirectory(ctx)
+ for _, src := range srcs {
+ if _, ok := builds[src.String()]; !ok {
+ builds[src.String()] = compDbEntry{
+ Directory: rootDir,
+ Arguments: getArguments(src, ctx, ccModule),
+ File: src.String(),
+ }
+ }
+ }
+}
+
+func evalAndSplitVariable(ctx android.SingletonContext, str string) ([]string, error) {
+ evaluated, err := ctx.Eval(pctx, str)
+ if err == nil {
+ return strings.Split(evaluated, " "), nil
+ }
+ return []string{""}, err
+}
+
+func getCompdbAndroidSrcRootDirectory(ctx android.SingletonContext) string {
+ srcPath, _ := filepath.Abs(android.PathForSource(ctx).String())
+ return srcPath
+}
diff --git a/cc/config/toolchain.go b/cc/config/toolchain.go
index 19d2828..ca863a7 100644
--- a/cc/config/toolchain.go
+++ b/cc/config/toolchain.go
@@ -85,8 +85,6 @@
AvailableLibraries() []string
Bionic() bool
-
- profileRuntimeLibrary() string
}
type toolchainBase struct {
@@ -171,10 +169,6 @@
return true
}
-func (t toolchainBase) profileRuntimeLibrary() string {
- return ""
-}
-
func (t toolchainBase) ToolPath() string {
return ""
}
@@ -246,12 +240,6 @@
}
func ProfileRuntimeLibrary(t Toolchain) string {
- lib := t.profileRuntimeLibrary()
- if lib != "" {
- // Return the directly exported profile library
- return lib
- }
- // Return the Android-specific library
return SanitizerRuntimeLibrary(t, "profile")
}
diff --git a/cc/config/x86_linux_bionic_host.go b/cc/config/x86_linux_bionic_host.go
index 290793e..a9fb1f6 100644
--- a/cc/config/x86_linux_bionic_host.go
+++ b/cc/config/x86_linux_bionic_host.go
@@ -151,10 +151,6 @@
return true
}
-func (t *toolchainLinuxBionic) profileRuntimeLibrary() string {
- return "libclang_rt.profile-x86_64"
-}
-
var toolchainLinuxBionicSingleton Toolchain = &toolchainLinuxBionic{}
func linuxBionicToolchainFactory(arch android.Arch) Toolchain {
diff --git a/cc/config/x86_linux_host.go b/cc/config/x86_linux_host.go
index 653f819..354500e 100644
--- a/cc/config/x86_linux_host.go
+++ b/cc/config/x86_linux_host.go
@@ -270,14 +270,6 @@
return "${config.LinuxX8664YasmFlags}"
}
-func (t *toolchainLinuxX86) profileRuntimeLibrary() string {
- return "libclang_rt.profile-i386"
-}
-
-func (t *toolchainLinuxX8664) profileRuntimeLibrary() string {
- return "libclang_rt.profile-x86_64"
-}
-
func (t *toolchainLinux) AvailableLibraries() []string {
return linuxAvailableLibraries
}
diff --git a/cc/coverage.go b/cc/coverage.go
index 671353c..391b118 100644
--- a/cc/coverage.go
+++ b/cc/coverage.go
@@ -16,7 +16,6 @@
import (
"android/soong/android"
- "android/soong/cc/config"
)
type CoverageProperties struct {
@@ -39,10 +38,6 @@
func (cov *coverage) begin(ctx BaseModuleContext) {}
func (cov *coverage) deps(ctx BaseModuleContext, deps Deps) Deps {
- if cov.Properties.CoverageEnabled {
- runtimeLibrary := config.ProfileRuntimeLibrary(ctx.toolchain())
- deps.LateStaticLibs = append(deps.LateStaticLibs, runtimeLibrary)
- }
return deps
}
@@ -104,8 +99,9 @@
if !mctx.DeviceConfig().NativeCoverageEnabled() {
// Coverage is disabled globally
- } else if mctx.Darwin() || mctx.Windows() {
- // Coverage not supported for Darwin and Windows
+ } else if mctx.Host() {
+ // TODO(dwillemsen): because of -nodefaultlibs, we must depend on libclang_rt.profile-*.a
+ // Just turn off for now.
} else if c.coverage.Properties.Native_coverage != nil {
enabled = *c.coverage.Properties.Native_coverage
} else {
diff --git a/docs/compdb.md b/docs/compdb.md
new file mode 100644
index 0000000..68927ca
--- /dev/null
+++ b/docs/compdb.md
@@ -0,0 +1,27 @@
+# Compdb (compile\_commands.json) Generator
+
+Soong can generate compdb files. This is intended for use with editing tools
+such as YouCompleteMe and other libclang based completers.
+
+compdb file generation is enabled via environment variable:
+
+```bash
+$ export SOONG_GEN_COMPDB=1
+$ export SOONG_GEN_COMPDB_DEBUG=1
+```
+
+One can make soong generate a symlink to the compdb file using an environment
+variable:
+
+```bash
+$ export SOONG_LINK_COMPDB_TO=$ANDROID_HOST_OUT
+```
+
+You can then trigger an empty build:
+
+```bash
+$ make nothing
+```
+
+Note that if you build using mm or other limited makes with these environment
+variables set the compdb will only include files in included modules.
diff --git a/java/droiddoc.go b/java/droiddoc.go
index 0700487..a29f0ba 100644
--- a/java/droiddoc.go
+++ b/java/droiddoc.go
@@ -256,7 +256,9 @@
func (j *Javadoc) genWhitelistPathPrefixes(whitelistPathPrefixes map[string]bool) {
for _, dir := range j.properties.Srcs_lib_whitelist_dirs {
for _, pkg := range j.properties.Srcs_lib_whitelist_pkgs {
- prefix := filepath.Join(dir, pkg)
+ // convert foo.bar.baz to foo/bar/baz
+ pkgAsPath := filepath.Join(strings.Split(pkg, ".")...)
+ prefix := filepath.Join(dir, pkgAsPath)
if _, found := whitelistPathPrefixes[prefix]; !found {
whitelistPathPrefixes[prefix] = true
}
diff --git a/java/sdk_library.go b/java/sdk_library.go
index 301ec61..13a9275 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -18,8 +18,11 @@
"android/soong/android"
"android/soong/genrule"
"fmt"
+ "io"
"path"
+ "sort"
"strings"
+ "sync"
"github.com/google/blueprint"
"github.com/google/blueprint/proptools"
@@ -43,6 +46,10 @@
systemApiStubsTag = dependencyTag{name: "system"}
)
+var (
+ javaSdkLibrariesLock sync.Mutex
+)
+
// java_sdk_library is to make a Java library that implements optional platform APIs to apps.
// It is actually a wrapper of several modules: 1) stubs library that clients are linked against
// to, 2) droiddoc module that internally generates API stubs source files, 3) the real runtime
@@ -62,6 +69,12 @@
android.PreArchMutators(func(ctx android.RegisterMutatorsContext) {
ctx.TopDown("java_sdk_library", sdkLibraryMutator).Parallel()
})
+
+ android.RegisterMakeVarsProvider(pctx, func(ctx android.MakeVarsContext) {
+ javaSdkLibraries := javaSdkLibraries(ctx.Config())
+ sort.Strings(*javaSdkLibraries)
+ ctx.Strict("JAVA_SDK_LIBRARIES", strings.Join(*javaSdkLibraries, " "))
+ })
}
type sdkLibraryProperties struct {
@@ -120,6 +133,20 @@
})
}
+func (module *sdkLibrary) AndroidMk() android.AndroidMkData {
+ // Create a phony module that installs the impl library, for the case when this lib is
+ // in PRODUCT_PACKAGES.
+ return android.AndroidMkData{
+ Custom: func(w io.Writer, name, prefix, moduleDir string, data android.AndroidMkData) {
+ fmt.Fprintln(w, "\ninclude $(CLEAR_VARS)")
+ fmt.Fprintln(w, "LOCAL_PATH :=", moduleDir)
+ fmt.Fprintln(w, "LOCAL_MODULE :=", name)
+ fmt.Fprintln(w, "LOCAL_REQUIRED_MODULES := "+module.implName())
+ fmt.Fprintln(w, "include $(BUILD_PHONY_PACKAGE)")
+ },
+ }
+}
+
// Module name of the stubs library
func (module *sdkLibrary) stubsName(forSystemApi bool) string {
stubsName := module.BaseModuleName() + sdkStubsLibrarySuffix
@@ -210,6 +237,9 @@
Unbundled_build struct {
Enabled *bool
}
+ Pdk struct {
+ Enabled *bool
+ }
}
}{}
@@ -219,6 +249,7 @@
props.Sdk_version = proptools.StringPtr(module.sdkVersion(forSystemApi))
// Unbundled apps will use the prebult one from /prebuilts/sdk
props.Product_variables.Unbundled_build.Enabled = proptools.BoolPtr(false)
+ props.Product_variables.Pdk.Enabled = proptools.BoolPtr(false)
if module.SocSpecific() {
props.Soc_specific = proptools.BoolPtr(true)
@@ -281,17 +312,25 @@
props.Api_filename = proptools.StringPtr(currentApiFileName)
props.Removed_api_filename = proptools.StringPtr(removedApiFileName)
- // Includes the main framework source to ensure that doclava has access to the
- // visibility information for the base classes of the mock classes. Without it
- // otherwise hidden methods could be visible.
- // TODO: remove the need for this
+ // Include the part of the framework source. This is required for the case when
+ // API class is extending from the framework class. In that case, doclava needs
+ // to know whether the base class is hidden or not. Since that information is
+ // encoded as @hide string in the comment, we need source files for the classes,
+ // not the compiled ones. Also there are rare cases where part of SDK library is
+ // implemented in the framework (e.g. org.apache.http.legacy). In that case,
+ // we need framework source to make API stubs, though the sources are not
+ // required to build the runtime library.
props.Srcs_lib = proptools.StringPtr("framework")
props.Srcs_lib_whitelist_dirs = []string{"core/java"}
- props.Srcs_lib_whitelist_pkgs = []string{"android"}
- // These libs are required by doclava to parse the sources from framework.
+ props.Srcs_lib_whitelist_pkgs = module.properties.Api_packages
+ // Add android.annotation package to give access to the framework-defined
+ // annotations such as SystemApi, NonNull, etc.
+ props.Srcs_lib_whitelist_pkgs = append(props.Srcs_lib_whitelist_pkgs, "android.annotation")
+ // These libs are required by doclava to parse the framework sources add via
+ // Src_lib and Src_lib_whitelist_* properties just above.
// If we don't add them to the classpath, errors messages are generated by doclava,
// though they don't break the build.
- props.Libs = append(props.Libs, "conscrypt", "bouncycastle", "okhttp")
+ props.Libs = append(props.Libs, "conscrypt", "bouncycastle", "okhttp", "framework")
mctx.CreateModule(android.ModuleFactoryAdaptor(DroiddocFactory), &props)
}
@@ -397,6 +436,12 @@
}
}
+func javaSdkLibraries(config android.Config) *[]string {
+ return config.Once("javaSdkLibraries", func() interface{} {
+ return &[]string{}
+ }).(*[]string)
+}
+
// For a java_sdk_library module, create internal modules for stubs, docs,
// runtime libs and xml file. If requested, the stubs and docs are created twice
// once for public API level and once for system API level
@@ -413,6 +458,12 @@
// for runtime
module.createXmlFile(mctx)
module.createImplLibrary(mctx)
+
+ // record java_sdk_library modules so that they are exported to make
+ javaSdkLibraries := javaSdkLibraries(mctx.Config())
+ javaSdkLibrariesLock.Lock()
+ defer javaSdkLibrariesLock.Unlock()
+ *javaSdkLibraries = append(*javaSdkLibraries, module.BaseModuleName())
}
}