Merge "Add Documentation for clion project generator"
diff --git a/Android.bp b/Android.bp
index 5e00a52..74da7c1 100644
--- a/Android.bp
+++ b/Android.bp
@@ -118,6 +118,7 @@
"cc/builder.go",
"cc/cc.go",
"cc/check.go",
+ "cc/coverage.go",
"cc/gen.go",
"cc/makevars.go",
"cc/prebuilt.go",
@@ -129,6 +130,7 @@
"cc/tidy.go",
"cc/util.go",
+ "cc/cmakelists.go",
"cc/compiler.go",
"cc/installer.go",
"cc/linker.go",
diff --git a/android/config.go b/android/config.go
index 76635b3..b4b0be8 100644
--- a/android/config.go
+++ b/android/config.go
@@ -472,10 +472,17 @@
return String(c.config.ProductVariables.BtConfigIncludeDir)
}
-func (c *deviceConfig) BtHcilpIncluded() string {
- return String(c.config.ProductVariables.BtHcilpIncluded)
+func (c *deviceConfig) NativeCoverageEnabled() bool {
+ return Bool(c.config.ProductVariables.NativeCoverage)
}
-func (c *deviceConfig) BtHciUseMct() bool {
- return Bool(c.config.ProductVariables.BtHciUseMct)
+func (c *deviceConfig) CoverageEnabledForPath(path string) bool {
+ if c.config.ProductVariables.CoveragePaths != nil {
+ for _, prefix := range *c.config.ProductVariables.CoveragePaths {
+ if strings.HasPrefix(path, prefix) {
+ return true
+ }
+ }
+ }
+ return false
}
diff --git a/android/env.go b/android/env.go
index 3b523a2..c7409e8 100644
--- a/android/env.go
+++ b/android/env.go
@@ -27,10 +27,6 @@
// compare the contents of the environment variables, rewriting the file if necessary to cause
// a manifest regeneration.
-func init() {
- RegisterSingletonType("env", EnvSingleton)
-}
-
func EnvSingleton() blueprint.Singleton {
return &envSingleton{}
}
diff --git a/android/register.go b/android/register.go
index 0ad9d30..d6b290d 100644
--- a/android/register.go
+++ b/android/register.go
@@ -77,6 +77,7 @@
handle.Parallel()
}
}
+ ctx.RegisterSingletonType("env", EnvSingleton)
return ctx
}
diff --git a/android/variable.go b/android/variable.go
index bb84be2..29f7c31 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -131,6 +131,9 @@
ClangTidy *bool `json:",omitempty"`
TidyChecks *string `json:",omitempty"`
+ NativeCoverage *bool `json:",omitempty"`
+ CoveragePaths *[]string `json:",omitempty"`
+
DevicePrefer32BitExecutables *bool `json:",omitempty"`
HostPrefer32BitExecutables *bool `json:",omitempty"`
@@ -141,8 +144,6 @@
ArtUseReadBarrier *bool `json:",omitempty"`
BtConfigIncludeDir *string `json:",omitempty"`
- BtHcilpIncluded *string `json:",omitempty"`
- BtHciUseMct *bool `json:",omitempty"`
}
func boolPtr(v bool) *bool {
diff --git a/cc/androidmk.go b/cc/androidmk.go
index a5a625f..ac1a55d 100644
--- a/cc/androidmk.go
+++ b/cc/androidmk.go
@@ -81,14 +81,14 @@
}
func (library *libraryDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) {
- if !library.static() {
+ if library.shared() {
ctx.subAndroidMk(ret, &library.stripper)
ctx.subAndroidMk(ret, &library.relocationPacker)
}
- if library.static() {
+ if library.static() || library.header() {
ret.Class = "STATIC_LIBRARIES"
- } else {
+ } else if library.shared() {
ret.Class = "SHARED_LIBRARIES"
}
@@ -111,10 +111,14 @@
fmt.Fprintln(w, "LOCAL_SYSTEM_SHARED_LIBRARIES :=")
+ if library.coverageOutputFile.Valid() {
+ fmt.Fprintln(w, "LOCAL_PREBUILT_COVERAGE_ARCHIVE :=", library.coverageOutputFile.String())
+ }
+
return nil
})
- if !library.static() {
+ if library.shared() {
ctx.subAndroidMk(ret, library.baseInstaller)
}
}
@@ -145,6 +149,9 @@
fmt.Fprintln(w, "LOCAL_MODULE_SYMLINKS := "+strings.Join(binary.symlinks, " "))
}
+ if binary.coverageOutputFile.Valid() {
+ fmt.Fprintln(w, "LOCAL_PREBUILT_COVERAGE_ARCHIVE :=", binary.coverageOutputFile.String())
+ }
return nil
})
}
diff --git a/cc/binary.go b/cc/binary.go
index afc8a99..521ccb7 100644
--- a/cc/binary.go
+++ b/cc/binary.go
@@ -79,6 +79,9 @@
// Names of symlinks to be installed for use in LOCAL_MODULE_SYMLINKS
symlinks []string
+
+ // Output archive of gcno coverage information
+ coverageOutputFile android.OptionalPath
}
var _ linker = (*binaryDecorator)(nil)
@@ -299,6 +302,10 @@
deps.LateStaticLibs, deps.WholeStaticLibs, linkerDeps, deps.CrtBegin, deps.CrtEnd, true,
builderFlags, outputFile)
+ objs.coverageFiles = append(objs.coverageFiles, deps.StaticLibObjs.coverageFiles...)
+ objs.coverageFiles = append(objs.coverageFiles, deps.WholeStaticLibObjs.coverageFiles...)
+ binary.coverageOutputFile = TransformCoverageFilesToLib(ctx, objs, builderFlags, binary.getStem(ctx))
+
return ret
}
diff --git a/cc/builder.go b/cc/builder.go
index c9a6722..9a871d5 100644
--- a/cc/builder.go
+++ b/cc/builder.go
@@ -198,6 +198,7 @@
toolchain config.Toolchain
clang bool
tidy bool
+ coverage bool
groupStaticLibs bool
@@ -207,21 +208,24 @@
}
type Objects struct {
- objFiles android.Paths
- tidyFiles android.Paths
+ objFiles android.Paths
+ tidyFiles android.Paths
+ coverageFiles android.Paths
}
func (a Objects) Copy() Objects {
return Objects{
- objFiles: append(android.Paths{}, a.objFiles...),
- tidyFiles: append(android.Paths{}, a.tidyFiles...),
+ objFiles: append(android.Paths{}, a.objFiles...),
+ tidyFiles: append(android.Paths{}, a.tidyFiles...),
+ coverageFiles: append(android.Paths{}, a.coverageFiles...),
}
}
func (a Objects) Append(b Objects) Objects {
return Objects{
- objFiles: append(a.objFiles, b.objFiles...),
- tidyFiles: append(a.tidyFiles, b.tidyFiles...),
+ objFiles: append(a.objFiles, b.objFiles...),
+ tidyFiles: append(a.tidyFiles, b.tidyFiles...),
+ coverageFiles: append(a.coverageFiles, b.coverageFiles...),
}
}
@@ -234,6 +238,10 @@
if flags.tidy && flags.clang {
tidyFiles = make(android.Paths, 0, len(srcFiles))
}
+ var coverageFiles android.Paths
+ if flags.coverage {
+ coverageFiles = make(android.Paths, 0, len(srcFiles))
+ }
cflags := flags.globalFlags + " " + flags.cFlags + " " + flags.conlyFlags
cppflags := flags.globalFlags + " " + flags.cFlags + " " + flags.cppFlags
@@ -268,12 +276,14 @@
var moduleCflags string
var ccCmd string
tidy := flags.tidy && flags.clang
+ coverage := flags.coverage
switch srcFile.Ext() {
case ".S", ".s":
ccCmd = "gcc"
moduleCflags = asflags
tidy = false
+ coverage = false
case ".c":
ccCmd = "gcc"
moduleCflags = cflags
@@ -300,11 +310,19 @@
ccCmd = gccCmd(flags.toolchain, ccCmd)
}
+ var implicitOutputs android.WritablePaths
+ if coverage {
+ gcnoFile := android.ObjPathWithExt(ctx, subdir, srcFile, "gcno")
+ implicitOutputs = append(implicitOutputs, gcnoFile)
+ coverageFiles = append(coverageFiles, gcnoFile)
+ }
+
ctx.ModuleBuild(pctx, android.ModuleBuildParams{
- Rule: cc,
- Output: objFile,
- Input: srcFile,
- OrderOnly: deps,
+ Rule: cc,
+ Output: objFile,
+ ImplicitOutputs: implicitOutputs,
+ Input: srcFile,
+ OrderOnly: deps,
Args: map[string]string{
"cFlags": moduleCflags,
"ccCmd": ccCmd,
@@ -332,8 +350,9 @@
}
return Objects{
- objFiles: objFiles,
- tidyFiles: tidyFiles,
+ objFiles: objFiles,
+ tidyFiles: tidyFiles,
+ coverageFiles: coverageFiles,
}
}
@@ -341,6 +360,11 @@
func TransformObjToStaticLib(ctx android.ModuleContext, objFiles android.Paths,
flags builderFlags, outputFile android.ModuleOutPath, deps android.Paths) {
+ if ctx.Darwin() {
+ transformDarwinObjToStaticLib(ctx, objFiles, flags, outputFile, deps)
+ return
+ }
+
arCmd := gccCmd(flags.toolchain, "ar")
arFlags := "crsPD"
@@ -360,7 +384,7 @@
// darwin. The darwin ar tool doesn't support @file for list files, and has a
// very small command line length limit, so we have to split the ar into multiple
// steps, each appending to the previous one.
-func TransformDarwinObjToStaticLib(ctx android.ModuleContext, objFiles android.Paths,
+func transformDarwinObjToStaticLib(ctx android.ModuleContext, objFiles android.Paths,
flags builderFlags, outputPath android.ModuleOutPath, deps android.Paths) {
arFlags := "cqs"
@@ -599,6 +623,20 @@
})
}
+func TransformCoverageFilesToLib(ctx android.ModuleContext,
+ inputs Objects, flags builderFlags, baseName string) android.OptionalPath {
+
+ if len(inputs.coverageFiles) > 0 {
+ outputFile := android.PathForModuleOut(ctx, baseName+".gcnodir")
+
+ TransformObjToStaticLib(ctx, inputs.coverageFiles, flags, outputFile, nil)
+
+ return android.OptionalPathForPath(outputFile)
+ }
+
+ return android.OptionalPath{}
+}
+
func CopyGccLib(ctx android.ModuleContext, libName string,
flags builderFlags, outputFile android.WritablePath) {
diff --git a/cc/cc.go b/cc/cc.go
index 8bf1467..d486db3 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -46,6 +46,8 @@
ctx.TopDown("tsan_deps", sanitizerDepsMutator(tsan))
ctx.BottomUp("tsan", sanitizerMutator(tsan)).Parallel()
+
+ ctx.BottomUp("coverage", coverageLinkingMutator).Parallel()
})
pctx.Import("android/soong/cc/config")
@@ -78,6 +80,7 @@
// Paths to .o files
Objs Objects
+ StaticLibObjs Objects
WholeStaticLibObjs Objects
// Paths to generated source files
@@ -108,6 +111,7 @@
Toolchain config.Toolchain
Clang bool
Tidy bool
+ Coverage bool
RequiredInstructionSet string
DynamicLinker string
@@ -144,8 +148,7 @@
}
type UnusedProperties struct {
- Native_coverage *bool
- Tags []string
+ Tags []string
}
type ModuleContextIntf interface {
@@ -261,6 +264,7 @@
installer installer
stl *stl
sanitize *sanitize
+ coverage *coverage
androidMkSharedLibDeps []string
@@ -269,6 +273,9 @@
cachedToolchain config.Toolchain
subAndroidMkOnce map[subAndroidMkProvider]bool
+
+ // Flags used to compile this module
+ flags Flags
}
func (c *Module) Init() (blueprint.Module, []interface{}) {
@@ -288,6 +295,9 @@
if c.sanitize != nil {
props = append(props, c.sanitize.props()...)
}
+ if c.coverage != nil {
+ props = append(props, c.coverage.props()...)
+ }
for _, feature := range c.features {
props = append(props, feature.props()...)
}
@@ -408,6 +418,7 @@
}
module.stl = &stl{}
module.sanitize = &sanitize{}
+ module.coverage = &coverage{}
return module
}
@@ -451,6 +462,9 @@
if c.sanitize != nil {
flags = c.sanitize.flags(ctx, flags)
}
+ if c.coverage != nil {
+ flags = c.coverage.flags(ctx, flags)
+ }
for _, feature := range c.features {
flags = feature.flags(ctx, flags)
}
@@ -462,6 +476,13 @@
flags.CppFlags, _ = filterList(flags.CppFlags, config.IllegalFlags)
flags.ConlyFlags, _ = filterList(flags.ConlyFlags, config.IllegalFlags)
+ deps := c.depsToPaths(ctx)
+ if ctx.Failed() {
+ return
+ }
+ flags.GlobalFlags = append(flags.GlobalFlags, deps.Flags...)
+ c.flags = flags
+
// Optimization to reduce size of build.ninja
// Replace the long list of flags for each file with a module-local variable
ctx.Variable(pctx, "cflags", strings.Join(flags.CFlags, " "))
@@ -471,13 +492,6 @@
flags.CppFlags = []string{"$cppflags"}
flags.AsFlags = []string{"$asflags"}
- deps := c.depsToPaths(ctx)
- if ctx.Failed() {
- return
- }
-
- flags.GlobalFlags = append(flags.GlobalFlags, deps.Flags...)
-
var objs Objects
if c.compiler != nil {
objs = c.compiler.compile(ctx, flags, deps)
@@ -522,6 +536,9 @@
if c.sanitize != nil {
c.sanitize.begin(ctx)
}
+ if c.coverage != nil {
+ c.coverage.begin(ctx)
+ }
for _, feature := range c.features {
feature.begin(ctx)
}
@@ -560,6 +577,9 @@
if c.sanitize != nil {
deps = c.sanitize.deps(ctx, deps)
}
+ if c.coverage != nil {
+ deps = c.coverage.deps(ctx, deps)
+ }
for _, feature := range c.features {
deps = feature.deps(ctx, deps)
}
@@ -948,6 +968,20 @@
depPaths.CrtEnd = linkFile
}
+ switch tag {
+ case staticDepTag, staticExportDepTag, lateStaticDepTag:
+ staticLib, ok := cc.linker.(libraryInterface)
+ if !ok || !staticLib.static() {
+ ctx.ModuleErrorf("module %q not a static library", name)
+ return
+ }
+
+ // When combining coverage files for shared libraries and executables, coverage files
+ // in static libraries act as if they were whole static libraries.
+ depPaths.StaticLibObjs.coverageFiles = append(depPaths.StaticLibObjs.coverageFiles,
+ staticLib.objs().coverageFiles...)
+ }
+
if ptr != nil {
if !linkFile.Valid() {
ctx.ModuleErrorf("module %q missing output file", name)
@@ -1021,6 +1055,7 @@
&StripProperties{},
&InstallerProperties{},
&TidyProperties{},
+ &CoverageProperties{},
)
return android.InitDefaultsModule(module, module, props...)
diff --git a/cc/check.go b/cc/check.go
index 340464e..d04b145 100644
--- a/cc/check.go
+++ b/cc/check.go
@@ -36,6 +36,8 @@
ctx.PropertyErrorf(prop, "Bad flag `%s`, use local_include_dirs or include_dirs instead", flag)
} else if inList(flag, config.IllegalFlags) {
ctx.PropertyErrorf(prop, "Illegal flag `%s`", flag)
+ } else if flag == "--coverage" {
+ ctx.PropertyErrorf(prop, "Bad flag: `%s`, use native_coverage instead", flag)
} else if strings.Contains(flag, " ") {
args := strings.Split(flag, " ")
if args[0] == "-include" {
@@ -73,6 +75,8 @@
ctx.PropertyErrorf(prop, "Bad flag: `%s` is not allowed", flag)
} else if strings.HasPrefix(flag, "-Wl,--version-script") {
ctx.PropertyErrorf(prop, "Bad flag: `%s`, use version_script instead", flag)
+ } else if flag == "--coverage" {
+ ctx.PropertyErrorf(prop, "Bad flag: `%s`, use native_coverage instead", flag)
} else if strings.Contains(flag, " ") {
args := strings.Split(flag, " ")
if args[0] == "-z" {
diff --git a/cc/cmakelists.go b/cc/cmakelists.go
new file mode 100644
index 0000000..1c47ec9
--- /dev/null
+++ b/cc/cmakelists.go
@@ -0,0 +1,382 @@
+package cc
+
+import (
+ "fmt"
+
+ "android/soong/android"
+ "android/soong/cc/config"
+ "github.com/google/blueprint"
+ "os"
+ "path"
+ "path/filepath"
+ "strings"
+)
+
+// This singleton generates CMakeLists.txt files. It does so for each blueprint Android.bp resulting in a cc.Module
+// when either make, mm, mma, mmm or mmma is called. CMakeLists.txt files are generated in a separate folder
+// structure (see variable CLionOutputProjectsDirectory for root).
+
+func init() {
+ android.RegisterSingletonType("cmakelists_generator", cMakeListsGeneratorSingleton)
+}
+
+func cMakeListsGeneratorSingleton() blueprint.Singleton {
+ return &cmakelistsGeneratorSingleton{}
+}
+
+type cmakelistsGeneratorSingleton struct{}
+
+const (
+ cMakeListsFilename = "CMakeLists.txt"
+ cLionAggregateProjectsDirectory = "development" + string(os.PathSeparator) + "ide" + string(os.PathSeparator) + "clion"
+ cLionOutputProjectsDirectory = "out" + string(os.PathSeparator) + cLionAggregateProjectsDirectory
+ minimumCMakeVersionSupported = "3.5"
+
+ // Environment variables used to modify behavior of this singleton.
+ envVariableGenerateCMakeLists = "SOONG_GEN_CMAKEFILES"
+ envVariableGenerateDebugInfo = "SOONG_GEN_CMAKEFILES_DEBUG"
+ envVariableTrue = "1"
+)
+
+// Instruct generator to trace how header include path and flags were generated.
+// This is done to ease investigating bug reports.
+var outputDebugInfo = false
+
+func (c *cmakelistsGeneratorSingleton) GenerateBuildActions(ctx blueprint.SingletonContext) {
+ if getEnvVariable(envVariableGenerateCMakeLists, ctx) != envVariableTrue {
+ return
+ }
+
+ outputDebugInfo = (getEnvVariable(envVariableGenerateDebugInfo, ctx) == envVariableTrue)
+
+ ctx.VisitAllModules(func(module blueprint.Module) {
+ if ccModule, ok := module.(*Module); ok {
+ if compiledModule, ok := ccModule.compiler.(CompiledInterface); ok {
+ generateCLionProject(compiledModule, ctx, ccModule)
+ }
+ }
+ })
+
+ // Link all handmade CMakeLists.txt aggregate from
+ // BASE/development/ide/clion to
+ // BASE/out/development/ide/clion.
+ dir := filepath.Join(getAndroidSrcRootDirectory(ctx), cLionAggregateProjectsDirectory)
+ filepath.Walk(dir, linkAggregateCMakeListsFiles)
+
+ return
+}
+
+func getEnvVariable(name string, ctx blueprint.SingletonContext) string {
+ // Using android.Config.Getenv instead of os.getEnv to guarantee soong will
+ // re-run in case this environment variable changes.
+ return ctx.Config().(android.Config).Getenv(name)
+}
+
+func exists(path string) bool {
+ _, err := os.Stat(path)
+ if err == nil {
+ return true
+ }
+ if os.IsNotExist(err) {
+ return false
+ }
+ return true
+}
+
+func linkAggregateCMakeListsFiles(path string, info os.FileInfo, err error) error {
+
+ if info == nil {
+ return nil
+ }
+
+ dst := strings.Replace(path, cLionAggregateProjectsDirectory, cLionOutputProjectsDirectory, 1)
+ if info.IsDir() {
+ // This is a directory to create
+ os.MkdirAll(dst, os.ModePerm)
+ } else {
+ // This is a file to link
+ os.Remove(dst)
+ os.Symlink(path, dst)
+ }
+ return nil
+}
+
+func generateCLionProject(compiledModule CompiledInterface, ctx blueprint.SingletonContext, ccModule *Module) {
+ srcs := compiledModule.Srcs()
+ if len(srcs) == 0 {
+ return
+ }
+
+ // Ensure the directory hosting the cmakelists.txt exists
+ clionproject_location := getCMakeListsForModule(ccModule, ctx)
+ projectDir := path.Dir(clionproject_location)
+ os.MkdirAll(projectDir, os.ModePerm)
+
+ // Create cmakelists.txt
+ f, _ := os.Create(filepath.Join(projectDir, cMakeListsFilename))
+ defer f.Close()
+
+ // Header.
+ f.WriteString("# THIS FILE WAS AUTOMATICALY GENERATED!\n")
+ f.WriteString("# ANY MODIFICATION WILL BE OVERWRITTEN!\n\n")
+ f.WriteString("# To improve project view in Clion :\n")
+ f.WriteString("# Tools > CMake > Change Project Root \n\n")
+ f.WriteString(fmt.Sprintf("cmake_minimum_required(VERSION %s)\n", minimumCMakeVersionSupported))
+ f.WriteString(fmt.Sprintf("project(%s)\n", ccModule.ModuleBase.Name()))
+ f.WriteString(fmt.Sprintf("set(ANDROID_ROOT %s)\n\n", getAndroidSrcRootDirectory(ctx)))
+
+ if ccModule.flags.Clang {
+ pathToCC, _ := evalVariable(ctx, "${config.ClangBin}/")
+ f.WriteString(fmt.Sprintf("set(CMAKE_C_COMPILER \"%s%s\")\n", buildCMakePath(pathToCC), "clang"))
+ f.WriteString(fmt.Sprintf("set(CMAKE_CXX_COMPILER \"%s%s\")\n", buildCMakePath(pathToCC), "clang++"))
+ } else {
+ toolchain := config.FindToolchain(ccModule.Os(), ccModule.Arch())
+ root, _ := evalVariable(ctx, toolchain.GccRoot())
+ triple, _ := evalVariable(ctx, toolchain.GccTriple())
+ pathToCC := filepath.Join(root, "bin", triple+"-")
+ f.WriteString(fmt.Sprintf("set(CMAKE_C_COMPILER \"%s%s\")\n", buildCMakePath(pathToCC), "gcc"))
+ f.WriteString(fmt.Sprintf("set(CMAKE_CXX_COMPILER \"%s%s\")\n", buildCMakePath(pathToCC), "g++"))
+ }
+ // Add all sources to the project.
+ f.WriteString("list(APPEND\n")
+ f.WriteString(" SOURCE_FILES\n")
+ for _, src := range srcs {
+ f.WriteString(fmt.Sprintf(" ${ANDROID_ROOT}/%s\n", src.String()))
+ }
+ f.WriteString(")\n")
+
+ // Add all header search path and compiler parameters (-D, -W, -f, -XXXX)
+ f.WriteString("\n# GLOBAL FLAGS:\n")
+ globalParameters := parseCompilerParameters(ccModule.flags.GlobalFlags, ctx, f)
+ translateToCMake(globalParameters, f, true, true)
+
+ f.WriteString("\n# CFLAGS:\n")
+ cParameters := parseCompilerParameters(ccModule.flags.CFlags, ctx, f)
+ translateToCMake(cParameters, f, true, true)
+
+ f.WriteString("\n# C ONLY FLAGS:\n")
+ cOnlyParameters := parseCompilerParameters(ccModule.flags.ConlyFlags, ctx, f)
+ translateToCMake(cOnlyParameters, f, true, false)
+
+ f.WriteString("\n# CPP FLAGS:\n")
+ cppParameters := parseCompilerParameters(ccModule.flags.CppFlags, ctx, f)
+ translateToCMake(cppParameters, f, false, true)
+
+ // Add project executable.
+ f.WriteString(fmt.Sprintf("\nadd_executable(%s ${SOURCE_FILES})\n", ccModule.ModuleBase.Name()))
+}
+
+func translateToCMake(c compilerParameters, f *os.File, cflags bool, cppflags bool) {
+ writeAllSystemDirectories(c.systemHeaderSearchPath, f)
+ writeAllIncludeDirectories(c.headerSearchPath, f)
+ if cflags {
+ writeAllFlags(c.flags, f, "CMAKE_C_FLAGS")
+ }
+
+ if cppflags {
+ writeAllFlags(c.flags, f, "CMAKE_CXX_FLAGS")
+ }
+ if c.sysroot != "" {
+ f.WriteString(fmt.Sprintf("include_directories(SYSTEM \"%s\")\n", buildCMakePath(path.Join(c.sysroot, "usr", "include"))))
+ }
+
+}
+
+func buildCMakePath(p string) string {
+ if path.IsAbs(p) {
+ return p
+ }
+ return fmt.Sprintf("${ANDROID_ROOT}/%s", p)
+}
+
+func writeAllIncludeDirectories(includes map[string]bool, f *os.File) {
+ for include := range includes {
+ f.WriteString(fmt.Sprintf("include_directories(\"%s\")\n", buildCMakePath(include)))
+ }
+}
+
+func writeAllSystemDirectories(includes map[string]bool, f *os.File) {
+ for include := range includes {
+ f.WriteString(fmt.Sprintf("include_directories(SYSTEM \"%s\")\n", buildCMakePath(include)))
+ }
+}
+
+func writeAllFlags(flags []string, f *os.File, tag string) {
+ for _, flag := range flags {
+ f.WriteString(fmt.Sprintf("set(%s \"${%s} %s\")\n", tag, tag, flag))
+ }
+}
+
+type parameterType int
+
+const (
+ headerSearchPath parameterType = iota
+ variable
+ systemHeaderSearchPath
+ flag
+ systemRoot
+)
+
+type compilerParameters struct {
+ headerSearchPath map[string]bool
+ systemHeaderSearchPath map[string]bool
+ flags []string
+ sysroot string
+}
+
+func makeCompilerParameters() compilerParameters {
+ return compilerParameters{
+ headerSearchPath: make(map[string]bool),
+ systemHeaderSearchPath: make(map[string]bool),
+ flags: make([]string, 0),
+ sysroot: "",
+ }
+}
+
+func categorizeParameter(parameter string) parameterType {
+ if strings.HasPrefix(parameter, "-I") {
+ return headerSearchPath
+ }
+ if strings.HasPrefix(parameter, "$") {
+ return variable
+ }
+ if strings.HasPrefix(parameter, "-isystem") {
+ return systemHeaderSearchPath
+ }
+ if strings.HasPrefix(parameter, "-isysroot") {
+ return systemRoot
+ }
+ if strings.HasPrefix(parameter, "--sysroot") {
+ return systemRoot
+ }
+ return flag
+}
+
+func parseCompilerParameters(params []string, ctx blueprint.SingletonContext, f *os.File) compilerParameters {
+ var compilerParameters = makeCompilerParameters()
+
+ for i, str := range params {
+ f.WriteString(fmt.Sprintf("# Raw param [%d] = '%s'\n", i, str))
+ }
+
+ for i := 0; i < len(params); i++ {
+ param := params[i]
+ if param == "" {
+ continue
+ }
+
+ switch categorizeParameter(param) {
+ case headerSearchPath:
+ compilerParameters.headerSearchPath[strings.TrimPrefix(param, "-I")] = true
+ case variable:
+ if evaluated, error := evalVariable(ctx, param); error == nil {
+ if outputDebugInfo {
+ f.WriteString(fmt.Sprintf("# variable %s = '%s'\n", param, evaluated))
+ }
+
+ paramsFromVar := parseCompilerParameters(strings.Split(evaluated, " "), ctx, f)
+ concatenateParams(&compilerParameters, paramsFromVar)
+
+ } else {
+ if outputDebugInfo {
+ f.WriteString(fmt.Sprintf("# variable %s could NOT BE RESOLVED\n", param))
+ }
+ }
+ case systemHeaderSearchPath:
+ if i < len(params)-1 {
+ compilerParameters.systemHeaderSearchPath[params[i+1]] = true
+ } else if outputDebugInfo {
+ f.WriteString("# Found a header search path marker with no path")
+ }
+ i = i + 1
+ case flag:
+ c := cleanupParameter(param)
+ f.WriteString(fmt.Sprintf("# FLAG '%s' became %s\n", param, c))
+ compilerParameters.flags = append(compilerParameters.flags, c)
+ case systemRoot:
+ if i < len(params)-1 {
+ compilerParameters.sysroot = params[i+1]
+ } else if outputDebugInfo {
+ f.WriteString("# Found a system root path marker with no path")
+ }
+ i = i + 1
+ }
+ }
+ return compilerParameters
+}
+
+func cleanupParameter(p string) string {
+ // In the blueprint, c flags can be passed as:
+ // cflags: [ "-DLOG_TAG=\"libEGL\"", ]
+ // which becomes:
+ // '-DLOG_TAG="libEGL"' in soong.
+ // In order to be injected in CMakelists.txt we need to:
+ // - Remove the wrapping ' character
+ // - Double escape all special \ and " characters.
+ // For a end result like:
+ // -DLOG_TAG=\\\"libEGL\\\"
+ if !strings.HasPrefix(p, "'") || !strings.HasSuffix(p, "'") || len(p) < 3 {
+ return p
+ }
+
+ // Reverse wrapper quotes and escaping that may have happened in NinjaAndShellEscape
+ // TODO: It is ok to reverse here for now but if NinjaAndShellEscape becomes more complex,
+ // we should create a method NinjaAndShellUnescape in escape.go and use that instead.
+ p = p[1 : len(p)-1]
+ p = strings.Replace(p, `'\''`, `'`, -1)
+ p = strings.Replace(p, `$$`, `$`, -1)
+
+ p = doubleEscape(p)
+ return p
+}
+
+func escape(s string) string {
+ s = strings.Replace(s, `\`, `\\`, -1)
+ s = strings.Replace(s, `"`, `\"`, -1)
+ return s
+}
+
+func doubleEscape(s string) string {
+ s = escape(s)
+ s = escape(s)
+ return s
+}
+
+func concatenateParams(c1 *compilerParameters, c2 compilerParameters) {
+ concatenateMaps(c1.headerSearchPath, c2.headerSearchPath)
+ concatenateMaps(c1.systemHeaderSearchPath, c2.systemHeaderSearchPath)
+ if c2.sysroot != "" {
+ c1.sysroot = c2.sysroot
+ }
+ c1.flags = append(c1.flags, c2.flags...)
+}
+
+func evalVariable(ctx blueprint.SingletonContext, str string) (string, error) {
+ evaluated, err := ctx.Eval(pctx, str)
+ if err == nil {
+ return evaluated, nil
+ }
+ return "", err
+}
+
+// Concatenate two maps into one. Results are stored in first operand.
+func concatenateMaps(map1 map[string]bool, map2 map[string]bool) {
+ for key, value := range map2 {
+ map1[key] = value
+ }
+}
+
+func getCMakeListsForModule(module *Module, ctx blueprint.SingletonContext) string {
+ return filepath.Join(getAndroidSrcRootDirectory(ctx),
+ cLionOutputProjectsDirectory,
+ path.Dir(ctx.BlueprintFile(module)),
+ module.ModuleBase.Name()+"-"+
+ module.ModuleBase.Arch().ArchType.Name+"-"+
+ module.ModuleBase.Os().Name,
+ cMakeListsFilename)
+}
+
+func getAndroidSrcRootDirectory(ctx blueprint.SingletonContext) string {
+ srcPath, _ := filepath.Abs(android.PathForSource(ctx).String())
+ return srcPath
+}
diff --git a/cc/compiler.go b/cc/compiler.go
index e962949..dc594e3 100644
--- a/cc/compiler.go
+++ b/cc/compiler.go
@@ -123,10 +123,20 @@
Properties BaseCompilerProperties
Proto ProtoProperties
deps android.Paths
+ srcs android.Paths
+ flags builderFlags
}
var _ compiler = (*baseCompiler)(nil)
+type CompiledInterface interface {
+ Srcs() android.Paths
+}
+
+func (compiler *baseCompiler) Srcs() android.Paths {
+ return compiler.srcs
+}
+
func (compiler *baseCompiler) appendCflags(flags []string) {
compiler.Properties.Cflags = append(compiler.Properties.Cflags, flags...)
}
@@ -429,6 +439,9 @@
compiler.deps = pathDeps
+ // Save src, buildFlags and context
+ compiler.srcs = srcs
+
// Compile files listed in c.Properties.Srcs into objects
objs := compileObjs(ctx, buildFlags, "", srcs, compiler.deps)
diff --git a/cc/config/global.go b/cc/config/global.go
index e254a1c..1ce1cce 100644
--- a/cc/config/global.go
+++ b/cc/config/global.go
@@ -145,6 +145,14 @@
})
pctx.StaticVariable("ClangAsanLibDir", "${ClangPath}/lib64/clang/${ClangShortVersion}/lib/linux")
+ // These are tied to the version of LLVM directly in external/llvm, so they might trail the host prebuilts
+ // being used for the rest of the build process.
+ pctx.SourcePathVariable("RSClangBase", "prebuilts/clang/host")
+ pctx.SourcePathVariable("RSClangVersion", "clang-3289846")
+ pctx.SourcePathVariable("RSReleaseVersion", "3.8")
+ pctx.StaticVariable("RSLLVMPrebuiltsPath", "${RSClangBase}/${HostPrebuiltTag}/${RSClangVersion}/bin")
+ pctx.StaticVariable("RSIncludePath", "${RSLLVMPrebuiltsPath}/../lib64/clang/${RSReleaseVersion}/include")
+
pctx.VariableFunc("CcWrapper", func(config interface{}) (string, error) {
if override := config.(android.Config).Getenv("CC_WRAPPER"); override != "" {
return override + " ", nil
diff --git a/cc/coverage.go b/cc/coverage.go
new file mode 100644
index 0000000..b1c8783
--- /dev/null
+++ b/cc/coverage.go
@@ -0,0 +1,124 @@
+// Copyright 2017 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 (
+ "android/soong/android"
+ "github.com/google/blueprint"
+)
+
+type CoverageProperties struct {
+ Native_coverage *bool
+
+ CoverageEnabled bool `blueprint:"mutated"`
+}
+
+type coverage struct {
+ Properties CoverageProperties
+
+ // Whether binaries containing this module need --coverage added to their ldflags
+ linkCoverage bool
+}
+
+func (cov *coverage) props() []interface{} {
+ return []interface{}{&cov.Properties}
+}
+
+func (cov *coverage) begin(ctx BaseModuleContext) {}
+
+func (cov *coverage) deps(ctx BaseModuleContext, deps Deps) Deps {
+ return deps
+}
+
+func (cov *coverage) flags(ctx ModuleContext, flags Flags) Flags {
+ if !ctx.DeviceConfig().NativeCoverageEnabled() {
+ return flags
+ }
+
+ if cov.Properties.CoverageEnabled {
+ flags.Coverage = true
+ flags.GlobalFlags = append(flags.GlobalFlags, "--coverage", "-O0")
+ cov.linkCoverage = true
+ }
+
+ // Even if we don't have coverage enabled, if any of our object files were compiled
+ // with coverage, then we need to add --coverage to our ldflags.
+ if !cov.linkCoverage {
+ if ctx.static() && !ctx.staticBinary() {
+ // For static libraries, the only thing that changes our object files
+ // are included whole static libraries, so check to see if any of
+ // those have coverage enabled.
+ ctx.VisitDirectDeps(func(m blueprint.Module) {
+ if ctx.OtherModuleDependencyTag(m) != wholeStaticDepTag {
+ return
+ }
+
+ if cc, ok := m.(*Module); ok && cc.coverage != nil {
+ if cc.coverage.linkCoverage {
+ cov.linkCoverage = true
+ }
+ }
+ })
+ } else {
+ // For executables and shared libraries, we need to check all of
+ // our static dependencies.
+ ctx.VisitDirectDeps(func(m blueprint.Module) {
+ cc, ok := m.(*Module)
+ if !ok || cc.coverage == nil {
+ return
+ }
+
+ if static, ok := cc.linker.(libraryInterface); !ok || !static.static() {
+ return
+ }
+
+ if cc.coverage.linkCoverage {
+ cov.linkCoverage = true
+ }
+ })
+ }
+ }
+
+ if cov.linkCoverage {
+ flags.LdFlags = append(flags.LdFlags, "--coverage")
+ }
+
+ return flags
+}
+
+func coverageLinkingMutator(mctx android.BottomUpMutatorContext) {
+ if c, ok := mctx.Module().(*Module); ok && c.coverage != nil {
+ var enabled bool
+
+ if !mctx.DeviceConfig().NativeCoverageEnabled() {
+ // Coverage is disabled globally
+ } 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 {
+ enabled = mctx.DeviceConfig().CoverageEnabledForPath(mctx.ModuleDir())
+ }
+
+ if enabled {
+ // Create a variation so that we don't need to recompile objects
+ // when turning on or off coverage. We'll still relink the necessary
+ // binaries, since we don't know which ones those are until later.
+ m := mctx.CreateLocalVariations("cov")
+ m[0].(*Module).coverage.Properties.CoverageEnabled = true
+ }
+ }
+}
diff --git a/cc/library.go b/cc/library.go
index 8474f96..f7194e4 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -64,7 +64,9 @@
// export headers generated from .proto sources
Export_proto_headers bool
}
+}
+type LibraryMutatedProperties struct {
VariantName string `blueprint:"mutated"`
// Build a static variant
@@ -175,7 +177,8 @@
// libraryDecorator wraps baseCompiler, baseLinker and baseInstaller to provide library-specific
// functionality: static vs. shared linkage, reusing object files for shared libraries
type libraryDecorator struct {
- Properties LibraryProperties
+ Properties LibraryProperties
+ MutatedProperties LibraryMutatedProperties
// For reusing static library objects for shared library
reuseObjects Objects
@@ -199,6 +202,9 @@
sanitize *sanitize
+ // Output archive of gcno coverage information files
+ coverageOutputFile android.OptionalPath
+
// Decorated interafaces
*baseCompiler
*baseLinker
@@ -210,6 +216,7 @@
props = append(props, library.baseLinker.linkerProps()...)
return append(props,
&library.Properties,
+ &library.MutatedProperties,
&library.flagExporter.Properties,
&library.stripper.StripProperties,
&library.relocationPacker.Properties)
@@ -227,11 +234,11 @@
if library.static() {
flags.CFlags = append(flags.CFlags, library.Properties.Static.Cflags...)
- } else {
+ } else if library.shared() {
flags.CFlags = append(flags.CFlags, library.Properties.Shared.Cflags...)
}
- if !library.static() {
+ if library.shared() {
libName := library.getLibName(ctx)
// GCC for Android assumes that -shared means -Bsymbolic, use -Wl,-shared instead
sharedFlag := "-Wl,-shared"
@@ -300,7 +307,7 @@
srcs := android.PathsForModuleSrc(ctx, library.Properties.Static.Srcs)
objs = objs.Append(compileObjs(ctx, buildFlags, android.DeviceStaticLibrary,
srcs, library.baseCompiler.deps))
- } else {
+ } else if library.shared() {
srcs := android.PathsForModuleSrc(ctx, library.Properties.Shared.Srcs)
objs = objs.Append(compileObjs(ctx, buildFlags, android.DeviceSharedLibrary,
srcs, library.baseCompiler.deps))
@@ -321,7 +328,8 @@
buildShared() bool
// Sets whether a specific variant is static or shared
- setStatic(bool)
+ setStatic()
+ setShared()
}
func (library *libraryDecorator) getLibName(ctx ModuleContext) string {
@@ -336,7 +344,7 @@
}
}
- return name + library.Properties.VariantName
+ return name + library.MutatedProperties.VariantName
}
func (library *libraryDecorator) linkerInit(ctx BaseModuleContext) {
@@ -359,7 +367,7 @@
library.Properties.Static.Whole_static_libs...)
deps.StaticLibs = append(deps.StaticLibs, library.Properties.Static.Static_libs...)
deps.SharedLibs = append(deps.SharedLibs, library.Properties.Static.Shared_libs...)
- } else {
+ } else if library.shared() {
if ctx.toolchain().Bionic() && !Bool(library.baseLinker.Properties.Nocrt) {
if !ctx.sdk() && !ctx.vndk() {
deps.CrtBegin = "crtbegin_so"
@@ -392,13 +400,13 @@
library.objects = library.objects.Append(objs)
outputFile := android.PathForModuleOut(ctx,
- ctx.ModuleName()+library.Properties.VariantName+staticLibraryExtension)
+ ctx.ModuleName()+library.MutatedProperties.VariantName+staticLibraryExtension)
+ builderFlags := flagsToBuilderFlags(flags)
- if ctx.Darwin() {
- TransformDarwinObjToStaticLib(ctx, library.objects.objFiles, flagsToBuilderFlags(flags), outputFile, objs.tidyFiles)
- } else {
- TransformObjToStaticLib(ctx, library.objects.objFiles, flagsToBuilderFlags(flags), outputFile, objs.tidyFiles)
- }
+ TransformObjToStaticLib(ctx, library.objects.objFiles, builderFlags, outputFile, objs.tidyFiles)
+
+ library.coverageOutputFile = TransformCoverageFilesToLib(ctx, library.objects, builderFlags,
+ ctx.ModuleName()+library.MutatedProperties.VariantName)
library.wholeStaticMissingDeps = ctx.GetMissingDependencies()
@@ -506,6 +514,10 @@
deps.StaticLibs, deps.LateStaticLibs, deps.WholeStaticLibs,
linkerDeps, deps.CrtBegin, deps.CrtEnd, false, builderFlags, outputFile)
+ objs.coverageFiles = append(objs.coverageFiles, deps.StaticLibObjs.coverageFiles...)
+ objs.coverageFiles = append(objs.coverageFiles, deps.WholeStaticLibObjs.coverageFiles...)
+ library.coverageOutputFile = TransformCoverageFilesToLib(ctx, objs, builderFlags, library.getLibName(ctx))
+
return ret
}
@@ -515,7 +527,7 @@
objs = objs.Append(deps.Objs)
var out android.Path
- if library.static() {
+ if library.static() || library.header() {
out = library.linkStatic(ctx, flags, deps, objs)
} else {
out = library.linkShared(ctx, flags, deps, objs)
@@ -548,12 +560,12 @@
}
func (library *libraryDecorator) buildStatic() bool {
- return library.Properties.BuildStatic &&
+ return library.MutatedProperties.BuildStatic &&
(library.Properties.Static.Enabled == nil || *library.Properties.Static.Enabled)
}
func (library *libraryDecorator) buildShared() bool {
- return library.Properties.BuildShared &&
+ return library.MutatedProperties.BuildShared &&
(library.Properties.Shared.Enabled == nil || *library.Properties.Shared.Enabled)
}
@@ -580,31 +592,45 @@
}
func (library *libraryDecorator) static() bool {
- return library.Properties.VariantIsStatic
+ return library.MutatedProperties.VariantIsStatic
}
-func (library *libraryDecorator) setStatic(static bool) {
- library.Properties.VariantIsStatic = static
+func (library *libraryDecorator) shared() bool {
+ return library.MutatedProperties.VariantIsShared
+}
+
+func (library *libraryDecorator) header() bool {
+ return !library.static() && !library.shared()
+}
+
+func (library *libraryDecorator) setStatic() {
+ library.MutatedProperties.VariantIsStatic = true
+ library.MutatedProperties.VariantIsShared = false
+}
+
+func (library *libraryDecorator) setShared() {
+ library.MutatedProperties.VariantIsStatic = false
+ library.MutatedProperties.VariantIsShared = true
}
func (library *libraryDecorator) BuildOnlyStatic() {
- library.Properties.BuildShared = false
+ library.MutatedProperties.BuildShared = false
}
func (library *libraryDecorator) BuildOnlyShared() {
- library.Properties.BuildStatic = false
+ library.MutatedProperties.BuildStatic = false
}
func (library *libraryDecorator) HeaderOnly() {
- library.Properties.BuildShared = false
- library.Properties.BuildStatic = false
+ library.MutatedProperties.BuildShared = false
+ library.MutatedProperties.BuildStatic = false
}
func NewLibrary(hod android.HostOrDeviceSupported) (*Module, *libraryDecorator) {
module := newModule(hod, android.MultilibBoth)
library := &libraryDecorator{
- Properties: LibraryProperties{
+ MutatedProperties: LibraryMutatedProperties{
BuildShared: true,
BuildStatic: true,
},
@@ -630,8 +656,8 @@
static := modules[0].(*Module)
shared := modules[1].(*Module)
- static.linker.(libraryInterface).setStatic(true)
- shared.linker.(libraryInterface).setStatic(false)
+ static.linker.(libraryInterface).setStatic()
+ shared.linker.(libraryInterface).setShared()
if staticCompiler, ok := static.compiler.(*libraryDecorator); ok {
sharedCompiler := shared.compiler.(*libraryDecorator)
@@ -645,10 +671,10 @@
}
} else if library.buildStatic() {
modules = mctx.CreateLocalVariations("static")
- modules[0].(*Module).linker.(libraryInterface).setStatic(true)
+ modules[0].(*Module).linker.(libraryInterface).setStatic()
} else if library.buildShared() {
modules = mctx.CreateLocalVariations("shared")
- modules[0].(*Module).linker.(libraryInterface).setStatic(false)
+ modules[0].(*Module).linker.(libraryInterface).setShared()
}
}
}
diff --git a/cc/makevars.go b/cc/makevars.go
index 30d83e8..e4d8fe6 100644
--- a/cc/makevars.go
+++ b/cc/makevars.go
@@ -40,6 +40,13 @@
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_CLANG", "${config.RSLLVMPrebuiltsPath}/clang")
+ ctx.Strict("RS_LLVM_AS", "${config.RSLLVMPrebuiltsPath}/llvm-as")
+ ctx.Strict("RS_LLVM_LINK", "${config.RSLLVMPrebuiltsPath}/llvm-link")
+
ctx.Strict("GLOBAL_CFLAGS_NO_OVERRIDE", "${config.NoOverrideGlobalCflags}")
ctx.Strict("GLOBAL_CLANG_CFLAGS_NO_OVERRIDE", "${config.ClangExtraNoOverrideCflags}")
ctx.Strict("GLOBAL_CPPFLAGS_NO_OVERRIDE", "")
@@ -57,6 +64,9 @@
ctx.Strict("ADDRESS_SANITIZER_CONFIG_EXTRA_LDFLAGS", asanLdflags)
ctx.Strict("ADDRESS_SANITIZER_CONFIG_EXTRA_STATIC_LIBRARIES", asanLibs)
+ ctx.Strict("CFI_EXTRA_CFLAGS", cfiCflags)
+ ctx.Strict("CFI_EXTRA_LDFLAGS", cfiLdflags)
+
ctx.Strict("DEFAULT_C_STD_VERSION", config.CStdVersion)
ctx.Strict("DEFAULT_CPP_STD_VERSION", config.CppStdVersion)
ctx.Strict("DEFAULT_GCC_CPP_STD_VERSION", config.GccCppStdVersion)
diff --git a/cc/ndk_library.go b/cc/ndk_library.go
index da3d5c7..6ebd0c4 100644
--- a/cc/ndk_library.go
+++ b/cc/ndk_library.go
@@ -335,7 +335,7 @@
module.linker = stub
module.installer = stub
- return module, []interface{}{&stub.properties}
+ return module, []interface{}{&stub.properties, &library.MutatedProperties}
}
func ndkLibraryFactory() (blueprint.Module, []interface{}) {
diff --git a/cc/ndk_prebuilt.go b/cc/ndk_prebuilt.go
index 676d63d..f1bd3b5 100644
--- a/cc/ndk_prebuilt.go
+++ b/cc/ndk_prebuilt.go
@@ -194,7 +194,7 @@
libName := strings.TrimPrefix(ctx.ModuleName(), "ndk_")
libExt := flags.Toolchain.ShlibSuffix()
- if ndk.Properties.BuildStatic {
+ if ndk.static() {
libExt = staticLibraryExtension
}
diff --git a/cc/sanitize.go b/cc/sanitize.go
index b98797a..28c6ef5 100644
--- a/cc/sanitize.go
+++ b/cc/sanitize.go
@@ -28,6 +28,12 @@
asanCflags = "-fno-omit-frame-pointer"
asanLdflags = "-Wl,-u,__asan_preinit"
asanLibs = "libasan"
+
+ cfiCflags = "-flto -fsanitize-cfi-cross-dso -fvisibility=default " +
+ "-fsanitize-blacklist=external/compiler-rt/lib/cfi/cfi_blacklist.txt"
+ // FIXME: revert the __cfi_check flag when clang is updated to r280031.
+ cfiLdflags = "-flto -fsanitize-cfi-cross-dso -fsanitize=cfi " +
+ "-Wl,-plugin-opt,O1 -Wl,-export-dynamic-symbol=__cfi_check"
)
type sanitizerType int
@@ -173,6 +179,12 @@
s.Diag.Cfi = nil
}
+ // Also disable CFI for arm32 until b/35157333 is fixed.
+ if ctx.Arch().ArchType == android.Arm {
+ s.Cfi = nil
+ s.Diag.Cfi = nil
+ }
+
if ctx.staticBinary() {
s.Address = nil
s.Coverage = nil
@@ -318,12 +330,8 @@
flags.LdFlags = append(flags.LdFlags, "-march=armv7-a")
}
sanitizers = append(sanitizers, "cfi")
- cfiFlags := []string{"-flto", "-fsanitize=cfi", "-fsanitize-cfi-cross-dso"}
- flags.CFlags = append(flags.CFlags, cfiFlags...)
- flags.CFlags = append(flags.CFlags, "-fvisibility=default")
- flags.LdFlags = append(flags.LdFlags, cfiFlags...)
- // FIXME: revert the __cfi_check flag when clang is updated to r280031.
- flags.LdFlags = append(flags.LdFlags, "-Wl,-plugin-opt,O1", "-Wl,-export-dynamic-symbol=__cfi_check")
+ flags.CFlags = append(flags.CFlags, cfiCflags)
+ flags.LdFlags = append(flags.LdFlags, cfiLdflags)
if Bool(sanitize.Properties.Sanitize.Diag.Cfi) {
diagSanitizers = append(diagSanitizers, "cfi")
}
diff --git a/cc/util.go b/cc/util.go
index 466266c..570052e 100644
--- a/cc/util.go
+++ b/cc/util.go
@@ -101,6 +101,7 @@
yasmFlags: strings.Join(in.YasmFlags, " "),
toolchain: in.Toolchain,
clang: in.Clang,
+ coverage: in.Coverage,
tidy: in.Tidy,
groupStaticLibs: in.GroupStaticLibs,
diff --git a/cmd/javac_filter/Android.bp b/cmd/javac_filter/Android.bp
new file mode 100644
index 0000000..cbdabb9
--- /dev/null
+++ b/cmd/javac_filter/Android.bp
@@ -0,0 +1,23 @@
+// Copyright 2017 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.
+
+blueprint_go_binary {
+ name: "soong_javac_filter",
+ srcs: [
+ "javac_filter.go",
+ ],
+ testSrcs: [
+ "javac_filter_test.go",
+ ],
+}
diff --git a/cmd/javac_filter/javac_filter.go b/cmd/javac_filter/javac_filter.go
new file mode 100644
index 0000000..32fcd63
--- /dev/null
+++ b/cmd/javac_filter/javac_filter.go
@@ -0,0 +1,105 @@
+// Copyright 2017 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.
+
+// soong_javac_filter expects the output of javac on stdin, and produces
+// an ANSI colorized version of the output on stdout.
+//
+// It also hides the unhelpful and unhideable "warning there is a warning"
+// messages.
+package main
+
+import (
+ "bufio"
+ "fmt"
+ "io"
+ "os"
+ "regexp"
+)
+
+// Regular expressions are based on
+// https://chromium.googlesource.com/chromium/src/+/master/build/android/gyp/javac.py
+// Colors are based on clang's output
+var (
+ filelinePrefix = `^[-.\w/\\]+.java:[0-9]+:`
+ warningRe = regexp.MustCompile(filelinePrefix + ` (warning:) .*$`)
+ errorRe = regexp.MustCompile(filelinePrefix + ` (.*?:) .*$`)
+ markerRe = regexp.MustCompile(`\s*(\^)\s*$`)
+
+ escape = "\x1b"
+ reset = escape + "[0m"
+ bold = escape + "[1m"
+ red = escape + "[31m"
+ green = escape + "[32m"
+ magenta = escape + "[35m"
+)
+
+func main() {
+ err := process(bufio.NewReader(os.Stdin), os.Stdout)
+ if err != nil {
+ fmt.Fprintln(os.Stderr, "reading standard input:", err)
+ os.Exit(-1)
+ }
+}
+
+func process(r io.Reader, w io.Writer) error {
+ scanner := bufio.NewScanner(r)
+ for scanner.Scan() {
+ processLine(w, scanner.Text())
+ }
+ return scanner.Err()
+}
+
+func processLine(w io.Writer, line string) {
+ for _, f := range filters {
+ if f.MatchString(line) {
+ return
+ }
+ }
+ for _, p := range colorPatterns {
+ var matched bool
+ if line, matched = applyColor(line, p.color, p.re); matched {
+ break
+ }
+ }
+ fmt.Fprintln(w, line)
+}
+
+// If line matches re, make it bold and apply color to the first submatch
+// Returns line, modified if it matched, and true if it matched.
+func applyColor(line, color string, re *regexp.Regexp) (string, bool) {
+ if m := re.FindStringSubmatchIndex(line); m != nil {
+ tagStart, tagEnd := m[2], m[3]
+ line = bold + line[:tagStart] +
+ color + line[tagStart:tagEnd] + reset + bold +
+ line[tagEnd:] + reset
+ return line, true
+ }
+ return line, false
+}
+
+var colorPatterns = []struct {
+ re *regexp.Regexp
+ color string
+}{
+ {warningRe, magenta},
+ {errorRe, red},
+ {markerRe, green},
+}
+
+var filters = []*regexp.Regexp{
+ regexp.MustCompile(`Note: (Some input files|.*\.java) uses? or overrides? a deprecated API.`),
+ regexp.MustCompile(`Note: Recompile with -Xlint:deprecation for details.`),
+ regexp.MustCompile(`Note: (Some input files|.*\.java) uses? unchecked or unsafe operations.`),
+ regexp.MustCompile(`Note: Recompile with -Xlint:unchecked for details.`),
+}
diff --git a/cmd/javac_filter/javac_filter_test.go b/cmd/javac_filter/javac_filter_test.go
new file mode 100644
index 0000000..43381ce
--- /dev/null
+++ b/cmd/javac_filter/javac_filter_test.go
@@ -0,0 +1,74 @@
+// Copyright 2017 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 main
+
+import (
+ "bytes"
+ "testing"
+)
+
+var testCases = []struct {
+ in, out string
+}{
+ {
+ in: "File.java:40: error: cannot find symbol\n",
+ out: "\x1b[1mFile.java:40: \x1b[31merror:\x1b[0m\x1b[1m cannot find symbol\x1b[0m\n",
+ },
+ {
+ in: "import static com.blah.SYMBOL;\n",
+ out: "import static com.blah.SYMBOL;\n",
+ },
+ {
+ in: " ^ \n",
+ out: "\x1b[1m \x1b[32m^\x1b[0m\x1b[1m \x1b[0m\n",
+ },
+ {
+ in: "File.java:398: warning: [RectIntersectReturnValueIgnored] Return value of com.blah.function() must be checked\n",
+ out: "\x1b[1mFile.java:398: \x1b[35mwarning:\x1b[0m\x1b[1m [RectIntersectReturnValueIgnored] Return value of com.blah.function() must be checked\x1b[0m\n",
+ },
+ {
+ in: " (see http://go/errorprone/bugpattern/RectIntersectReturnValueIgnored.md)\n",
+ out: " (see http://go/errorprone/bugpattern/RectIntersectReturnValueIgnored.md)\n",
+ },
+ {
+ in: `
+Note: Some input files use or override a deprecated API.
+Note: Recompile with -Xlint:deprecation for details.
+Note: Some input files use unchecked or unsafe operations.
+Note: Recompile with -Xlint:unchecked for details.
+Note: dir/file.java uses or overrides a deprecated API.
+Note: dir/file.java uses unchecked or unsafe operations.
+`,
+ out: "\n",
+ },
+ {
+ in: "\n",
+ out: "\n",
+ },
+}
+
+func TestJavacColorize(t *testing.T) {
+ for _, test := range testCases {
+ buf := new(bytes.Buffer)
+ err := process(bytes.NewReader([]byte(test.in)), buf)
+ if err != nil {
+ t.Errorf("error: %q", err)
+ }
+ got := string(buf.Bytes())
+ if got != test.out {
+ t.Errorf("expected %q got %q", test.out, got)
+ }
+ }
+}
diff --git a/cmd/multiproduct_kati/main.go b/cmd/multiproduct_kati/main.go
index 2ff19ce..21d8383 100644
--- a/cmd/multiproduct_kati/main.go
+++ b/cmd/multiproduct_kati/main.go
@@ -102,7 +102,7 @@
log.Println("Output directory:", *outDir)
build.SetupOutDir(buildCtx, config)
- log.SetOutput(filepath.Join(config.OutDir(), "build.log"))
+ log.SetOutput(filepath.Join(config.OutDir(), "soong.log"))
trace.SetOutput(filepath.Join(config.OutDir(), "build.trace"))
vars, err := build.DumpMakeVars(buildCtx, config, nil, nil, []string{"all_named_products"})
@@ -137,7 +137,7 @@
}
productLog := logger.New(&bytes.Buffer{})
- productLog.SetOutput(filepath.Join(productOutDir, "build.log"))
+ productLog.SetOutput(filepath.Join(productOutDir, "soong.log"))
productCtx := build.Context{&build.ContextImpl{
Context: ctx,
diff --git a/cmd/soong_ui/main.go b/cmd/soong_ui/main.go
index de941f4..06a601e 100644
--- a/cmd/soong_ui/main.go
+++ b/cmd/soong_ui/main.go
@@ -70,8 +70,15 @@
log.SetVerbose(config.IsVerbose())
build.SetupOutDir(buildCtx, config)
- log.SetOutput(filepath.Join(config.OutDir(), "build.log"))
- trace.SetOutput(filepath.Join(config.OutDir(), "build.trace"))
+
+ if config.Dist() {
+ os.MkdirAll(config.DistDir(), 0777)
+ log.SetOutput(filepath.Join(config.DistDir(), "logs", "soong.log"))
+ trace.SetOutput(filepath.Join(config.DistDir(), "logs", "build.trace"))
+ } else {
+ log.SetOutput(filepath.Join(config.OutDir(), "soong.log"))
+ trace.SetOutput(filepath.Join(config.OutDir(), "build.trace"))
+ }
if start, ok := os.LookupEnv("TRACE_BEGIN_SOONG"); ok {
if !strings.HasSuffix(start, "N") {
diff --git a/ui/build/config.go b/ui/build/config.go
index 35c5213..4853643 100644
--- a/ui/build/config.go
+++ b/ui/build/config.go
@@ -35,6 +35,7 @@
parallel int
keepGoing int
verbose bool
+ dist bool
// From the product config
katiArgs []string
@@ -90,6 +91,8 @@
} else if arg == "showcommands" {
ret.verbose = true
continue
+ } else if arg == "dist" {
+ ret.dist = true
}
if arg[0] == '-' {
var err error
@@ -183,6 +186,13 @@
return "out"
}
+func (c *configImpl) DistDir() string {
+ if distDir, ok := c.environ.Get("DIST_DIR"); ok {
+ return distDir
+ }
+ return filepath.Join(c.OutDir(), "dist")
+}
+
func (c *configImpl) NinjaArgs() []string {
return c.ninjaArgs
}
@@ -198,6 +208,10 @@
panic("SetKatiSuffix has not been called")
}
+func (c *configImpl) Dist() bool {
+ return c.dist
+}
+
func (c *configImpl) IsVerbose() bool {
return c.verbose
}
diff --git a/ui/build/soong.go b/ui/build/soong.go
index d017e70..6554f1d 100644
--- a/ui/build/soong.go
+++ b/ui/build/soong.go
@@ -50,6 +50,7 @@
env := config.Environment().Copy()
env.Set("SKIP_NINJA", "true")
cmd.Env = env.Environ()
+ cmd.Stdin = ctx.Stdin()
cmd.Stdout = ctx.Stdout()
cmd.Stderr = ctx.Stderr()
ctx.Verboseln(cmd.Path, cmd.Args)