Merge "Implement DPI variants in android_app_import."
diff --git a/cc/config/global.go b/cc/config/global.go
index 0a7d984..24075d9 100644
--- a/cc/config/global.go
+++ b/cc/config/global.go
@@ -84,6 +84,7 @@
"-Wl,--fatal-warnings",
"-Wl,--no-undefined-version",
"-Wl,--exclude-libs,libgcc.a",
+ "-Wl,--exclude-libs,libgcc_stripped.a",
}
deviceGlobalLldflags = append(ClangFilterUnknownLldflags(deviceGlobalLdflags),
diff --git a/cmd/soong_ui/main.go b/cmd/soong_ui/main.go
index d6999c5..5f9bd01 100644
--- a/cmd/soong_ui/main.go
+++ b/cmd/soong_ui/main.go
@@ -32,42 +32,89 @@
"android/soong/ui/tracer"
)
+// A command represents an operation to be executed in the soong build
+// system.
+type command struct {
+ // the flag name (must have double dashes)
+ flag string
+
+ // description for the flag (to display when running help)
+ description string
+
+ // Creates the build configuration based on the args and build context.
+ config func(ctx build.Context, args ...string) build.Config
+
+ // Returns what type of IO redirection this Command requires.
+ stdio func() terminal.StdioInterface
+
+ // run the command
+ run func(ctx build.Context, config build.Config, args []string, logsDir string)
+}
+
+const makeModeFlagName = "--make-mode"
+
+// list of supported commands (flags) supported by soong ui
+var commands []command = []command{
+ {
+ flag: makeModeFlagName,
+ description: "build the modules by the target name (i.e. soong_docs)",
+ config: func(ctx build.Context, args ...string) build.Config {
+ return build.NewConfig(ctx, args...)
+ },
+ stdio: func() terminal.StdioInterface {
+ return terminal.StdioImpl{}
+ },
+ run: make,
+ }, {
+ flag: "--dumpvar-mode",
+ description: "print the value of the legacy make variable VAR to stdout",
+ config: dumpVarConfig,
+ stdio: customStdio,
+ run: dumpVar,
+ }, {
+ flag: "--dumpvars-mode",
+ description: "dump the values of one or more legacy make variables, in shell syntax",
+ config: dumpVarConfig,
+ stdio: customStdio,
+ run: dumpVars,
+ },
+}
+
+// indexList returns the index of first found s. -1 is return if s is not
+// found.
func indexList(s string, list []string) int {
for i, l := range list {
if l == s {
return i
}
}
-
return -1
}
+// inList returns true if one or more of s is in the list.
func inList(s string, list []string) bool {
return indexList(s, list) != -1
}
+// Main execution of soong_ui. The command format is as follows:
+//
+// soong_ui <command> [<arg 1> <arg 2> ... <arg n>]
+//
+// Command is the type of soong_ui execution. Only one type of
+// execution is specified. The args are specific to the command.
func main() {
- var stdio terminal.StdioInterface
- stdio = terminal.StdioImpl{}
-
- // dumpvar uses stdout, everything else should be in stderr
- if os.Args[1] == "--dumpvar-mode" || os.Args[1] == "--dumpvars-mode" {
- stdio = terminal.NewCustomStdio(os.Stdin, os.Stderr, os.Stderr)
+ c, args := getCommand(os.Args)
+ if c == nil {
+ fmt.Fprintf(os.Stderr, "The `soong` native UI is not yet available.\n")
+ os.Exit(1)
}
- writer := terminal.NewWriter(stdio)
+ writer := terminal.NewWriter(c.stdio())
defer writer.Finish()
log := logger.New(writer)
defer log.Cleanup()
- if len(os.Args) < 2 || !(inList("--make-mode", os.Args) ||
- os.Args[1] == "--dumpvars-mode" ||
- os.Args[1] == "--dumpvar-mode") {
-
- log.Fatalln("The `soong` native UI is not yet available.")
- }
-
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
@@ -96,12 +143,8 @@
Writer: writer,
Status: stat,
}}
- var config build.Config
- if os.Args[1] == "--dumpvars-mode" || os.Args[1] == "--dumpvar-mode" {
- config = build.NewConfig(buildCtx)
- } else {
- config = build.NewConfig(buildCtx, os.Args[1:]...)
- }
+
+ config := c.config(buildCtx, args...)
build.SetupOutDir(buildCtx, config)
@@ -136,31 +179,10 @@
defer f.Shutdown()
build.FindSources(buildCtx, config, f)
- if os.Args[1] == "--dumpvar-mode" {
- dumpVar(buildCtx, config, os.Args[2:])
- } else if os.Args[1] == "--dumpvars-mode" {
- dumpVars(buildCtx, config, os.Args[2:])
- } else {
- if config.IsVerbose() {
- writer.Print("! The argument `showcommands` is no longer supported.")
- writer.Print("! Instead, the verbose log is always written to a compressed file in the output dir:")
- writer.Print("!")
- writer.Print(fmt.Sprintf("! gzip -cd %s/verbose.log.gz | less -R", logsDir))
- writer.Print("!")
- writer.Print("! Older versions are saved in verbose.log.#.gz files")
- writer.Print("")
- time.Sleep(5 * time.Second)
- }
-
- toBuild := build.BuildAll
- if config.Checkbuild() {
- toBuild |= build.RunBuildTests
- }
- build.Build(buildCtx, config, toBuild)
- }
+ c.run(buildCtx, config, args, logsDir)
}
-func dumpVar(ctx build.Context, config build.Config, args []string) {
+func dumpVar(ctx build.Context, config build.Config, args []string, _ string) {
flags := flag.NewFlagSet("dumpvar", flag.ExitOnError)
flags.Usage = func() {
fmt.Fprintf(os.Stderr, "usage: %s --dumpvar-mode [--abs] <VAR>\n\n", os.Args[0])
@@ -210,7 +232,7 @@
}
}
-func dumpVars(ctx build.Context, config build.Config, args []string) {
+func dumpVars(ctx build.Context, config build.Config, args []string, _ string) {
flags := flag.NewFlagSet("dumpvars", flag.ExitOnError)
flags.Usage = func() {
fmt.Fprintf(os.Stderr, "usage: %s --dumpvars-mode [--vars=\"VAR VAR ...\"]\n\n", os.Args[0])
@@ -277,3 +299,59 @@
fmt.Printf("%s%s='%s'\n", *absVarPrefix, name, strings.Join(res, " "))
}
}
+
+func customStdio() terminal.StdioInterface {
+ return terminal.NewCustomStdio(os.Stdin, os.Stderr, os.Stderr)
+}
+
+// dumpVarConfig does not require any arguments to be parsed by the NewConfig.
+func dumpVarConfig(ctx build.Context, args ...string) build.Config {
+ return build.NewConfig(ctx)
+}
+
+func make(ctx build.Context, config build.Config, _ []string, logsDir string) {
+ if config.IsVerbose() {
+ writer := ctx.Writer
+ writer.Print("! The argument `showcommands` is no longer supported.")
+ writer.Print("! Instead, the verbose log is always written to a compressed file in the output dir:")
+ writer.Print("!")
+ writer.Print(fmt.Sprintf("! gzip -cd %s/verbose.log.gz | less -R", logsDir))
+ writer.Print("!")
+ writer.Print("! Older versions are saved in verbose.log.#.gz files")
+ writer.Print("")
+ time.Sleep(5 * time.Second)
+ }
+
+ toBuild := build.BuildAll
+ if config.Checkbuild() {
+ toBuild |= build.RunBuildTests
+ }
+ build.Build(ctx, config, toBuild)
+}
+
+// getCommand finds the appropriate command based on args[1] flag. args[0]
+// is the soong_ui filename.
+func getCommand(args []string) (*command, []string) {
+ if len(args) < 2 {
+ return nil, args
+ }
+
+ for _, c := range commands {
+ if c.flag == args[1] {
+ return &c, args[2:]
+ }
+
+ // special case for --make-mode: if soong_ui was called from
+ // build/make/core/main.mk, the makeparallel with --ninja
+ // option specified puts the -j<num> before --make-mode.
+ // TODO: Remove this hack once it has been fixed.
+ if c.flag == makeModeFlagName {
+ if inList(makeModeFlagName, args) {
+ return &c, args[1:]
+ }
+ }
+ }
+
+ // command not found
+ return nil, args
+}
diff --git a/java/aar.go b/java/aar.go
index 5e1f88e..7332e76 100644
--- a/java/aar.go
+++ b/java/aar.go
@@ -647,6 +647,10 @@
return nil
}
+func (a *AARImport) SrcJarArgs() ([]string, android.Paths) {
+ return nil, nil
+}
+
var _ android.PrebuiltInterface = (*Import)(nil)
// android_library_import imports an `.aar` file into the build graph as if it was built with android_library.
diff --git a/java/device_host_converter.go b/java/device_host_converter.go
index 9c883e5..b92f4d7 100644
--- a/java/device_host_converter.go
+++ b/java/device_host_converter.go
@@ -34,6 +34,9 @@
implementationAndResourceJars android.Paths
resourceJars android.Paths
+ srcJarArgs []string
+ srcJarDeps android.Paths
+
combinedHeaderJar android.Path
combinedImplementationJar android.Path
}
@@ -100,6 +103,10 @@
d.implementationJars = append(d.implementationJars, dep.ImplementationJars()...)
d.implementationAndResourceJars = append(d.implementationAndResourceJars, dep.ImplementationAndResourcesJars()...)
d.resourceJars = append(d.resourceJars, dep.ResourceJars()...)
+
+ srcJarArgs, srcJarDeps := dep.SrcJarArgs()
+ d.srcJarArgs = append(d.srcJarArgs, srcJarArgs...)
+ d.srcJarDeps = append(d.srcJarDeps, srcJarDeps...)
} else {
ctx.PropertyErrorf("libs", "module %q cannot be used as a dependency", ctx.OtherModuleName(m))
}
@@ -157,6 +164,10 @@
return nil
}
+func (d *DeviceHostConverter) SrcJarArgs() ([]string, android.Paths) {
+ return d.srcJarArgs, d.srcJarDeps
+}
+
func (d *DeviceHostConverter) AndroidMk() android.AndroidMkData {
return android.AndroidMkData{
Class: "JAVA_LIBRARIES",
diff --git a/java/java.go b/java/java.go
index 47dd957..e764ec3 100644
--- a/java/java.go
+++ b/java/java.go
@@ -290,6 +290,10 @@
// jar file containing only resources including from static library dependencies
resourceJar android.Path
+ // args and dependencies to package source files into a srcjar
+ srcJarArgs []string
+ srcJarDeps android.Paths
+
// jar file containing implementation classes and resources including static library
// dependencies
implementationAndResourcesJar android.Path
@@ -340,6 +344,9 @@
// list of additional targets for checkbuild
additionalCheckedModules android.Paths
+ // Extra files generated by the module type to be added as java resources.
+ extraResources android.Paths
+
hiddenAPI
dexpreopter
}
@@ -362,6 +369,7 @@
DexJar() android.Path
AidlIncludeDirs() android.Paths
ExportedSdkLibs() []string
+ SrcJarArgs() ([]string, android.Paths)
}
type SdkLibraryDependency interface {
@@ -1110,9 +1118,18 @@
}
}
+ j.srcJarArgs, j.srcJarDeps = resourcePathsToJarArgs(srcFiles), srcFiles
+
+ var includeSrcJar android.WritablePath
+ if Bool(j.properties.Include_srcs) {
+ includeSrcJar = android.PathForModuleOut(ctx, ctx.ModuleName()+".srcjar")
+ TransformResourcesToJar(ctx, includeSrcJar, j.srcJarArgs, j.srcJarDeps)
+ }
+
dirArgs, dirDeps := ResourceDirsToJarArgs(ctx, j.properties.Java_resource_dirs,
j.properties.Exclude_java_resource_dirs, j.properties.Exclude_java_resources)
fileArgs, fileDeps := ResourceFilesToJarArgs(ctx, j.properties.Java_resources, j.properties.Exclude_java_resources)
+ extraArgs, extraDeps := resourcePathsToJarArgs(j.extraResources), j.extraResources
var resArgs []string
var resDeps android.Paths
@@ -1123,11 +1140,8 @@
resArgs = append(resArgs, fileArgs...)
resDeps = append(resDeps, fileDeps...)
- if Bool(j.properties.Include_srcs) {
- srcArgs, srcDeps := SourceFilesToJarArgs(ctx, j.properties.Srcs, j.properties.Exclude_srcs)
- resArgs = append(resArgs, srcArgs...)
- resDeps = append(resDeps, srcDeps...)
- }
+ resArgs = append(resArgs, extraArgs...)
+ resDeps = append(resDeps, extraDeps...)
if len(resArgs) > 0 {
resourceJar := android.PathForModuleOut(ctx, "res", jarName)
@@ -1138,17 +1152,22 @@
}
}
- if len(deps.staticResourceJars) > 0 {
- var jars android.Paths
- if j.resourceJar != nil {
- jars = append(jars, j.resourceJar)
- }
- jars = append(jars, deps.staticResourceJars...)
+ var resourceJars android.Paths
+ if j.resourceJar != nil {
+ resourceJars = append(resourceJars, j.resourceJar)
+ }
+ if Bool(j.properties.Include_srcs) {
+ resourceJars = append(resourceJars, includeSrcJar)
+ }
+ resourceJars = append(resourceJars, deps.staticResourceJars...)
+ if len(resourceJars) > 1 {
combinedJar := android.PathForModuleOut(ctx, "res-combined", jarName)
- TransformJarsToJar(ctx, combinedJar, "for resources", jars, android.OptionalPath{},
+ TransformJarsToJar(ctx, combinedJar, "for resources", resourceJars, android.OptionalPath{},
false, nil, nil)
j.resourceJar = combinedJar
+ } else if len(resourceJars) == 1 {
+ j.resourceJar = resourceJars[0]
}
jars = append(jars, deps.staticJars...)
@@ -1436,6 +1455,10 @@
return j.exportedSdkLibs
}
+func (j *Module) SrcJarArgs() ([]string, android.Paths) {
+ return j.srcJarArgs, j.srcJarDeps
+}
+
var _ logtagsProducer = (*Module)(nil)
func (j *Module) logtags() android.Paths {
@@ -1913,6 +1936,10 @@
return j.exportedSdkLibs
}
+func (j *Import) SrcJarArgs() ([]string, android.Paths) {
+ return nil, nil
+}
+
// Add compile time check for interface implementation
var _ android.IDEInfo = (*Import)(nil)
var _ android.IDECustomizedModuleName = (*Import)(nil)
diff --git a/java/java_resources.go b/java/java_resources.go
index 7161168..787d74a 100644
--- a/java/java_resources.go
+++ b/java/java_resources.go
@@ -85,19 +85,19 @@
return resourceFilesToJarArgs(ctx, res, exclude)
}
-// Convert java_resources properties to arguments to soong_zip -jar, keeping files that should
-// normally not used as resources like *.java
-func SourceFilesToJarArgs(ctx android.ModuleContext,
- res, exclude []string) (args []string, deps android.Paths) {
-
- return resourceFilesToJarArgs(ctx, res, exclude)
-}
-
func resourceFilesToJarArgs(ctx android.ModuleContext,
res, exclude []string) (args []string, deps android.Paths) {
files := android.PathsForModuleSrcExcludes(ctx, res, exclude)
+ args = resourcePathsToJarArgs(files)
+
+ return args, files
+}
+
+func resourcePathsToJarArgs(files android.Paths) []string {
+ var args []string
+
lastDir := ""
for i, f := range files {
rel := f.Rel()
@@ -113,5 +113,5 @@
lastDir = dir
}
- return args, files
+ return args
}
diff --git a/java/java_test.go b/java/java_test.go
index 4b850ef..3d8baee 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -484,12 +484,6 @@
args: "-C java-res -f java-res/a/a -f java-res/b/b",
},
{
- // Test that a module with "include_srcs: true" includes its source files in the resources jar
- name: "include sources",
- prop: `include_srcs: true`,
- args: "-C . -f a.java -f b.java -f c.java",
- },
- {
// Test that a module with wildcards in java_resource_dirs has the correct path prefixes
name: "wildcard dirs",
prop: `java_resource_dirs: ["java-res/*"]`,
@@ -557,6 +551,69 @@
}
}
+func TestIncludeSrcs(t *testing.T) {
+ ctx := testJava(t, `
+ java_library {
+ name: "foo",
+ srcs: [
+ "a.java",
+ "b.java",
+ "c.java",
+ ],
+ include_srcs: true,
+ }
+
+ java_library {
+ name: "bar",
+ srcs: [
+ "a.java",
+ "b.java",
+ "c.java",
+ ],
+ java_resource_dirs: ["java-res"],
+ include_srcs: true,
+ }
+ `)
+
+ // Test a library with include_srcs: true
+ foo := ctx.ModuleForTests("foo", "android_common").Output("withres/foo.jar")
+ fooSrcJar := ctx.ModuleForTests("foo", "android_common").Output("foo.srcjar")
+
+ if g, w := fooSrcJar.Output.String(), foo.Inputs.Strings(); !inList(g, w) {
+ t.Errorf("foo combined jars %v does not contain %q", w, g)
+ }
+
+ if g, w := fooSrcJar.Args["jarArgs"], "-C . -f a.java -f b.java -f c.java"; g != w {
+ t.Errorf("foo source jar args %q is not %q", w, g)
+ }
+
+ // Test a library with include_srcs: true and resources
+ bar := ctx.ModuleForTests("bar", "android_common").Output("withres/bar.jar")
+ barResCombined := ctx.ModuleForTests("bar", "android_common").Output("res-combined/bar.jar")
+ barRes := ctx.ModuleForTests("bar", "android_common").Output("res/bar.jar")
+ barSrcJar := ctx.ModuleForTests("bar", "android_common").Output("bar.srcjar")
+
+ if g, w := barSrcJar.Output.String(), barResCombined.Inputs.Strings(); !inList(g, w) {
+ t.Errorf("bar combined resource jars %v does not contain %q", w, g)
+ }
+
+ if g, w := barRes.Output.String(), barResCombined.Inputs.Strings(); !inList(g, w) {
+ t.Errorf("bar combined resource jars %v does not contain %q", w, g)
+ }
+
+ if g, w := barResCombined.Output.String(), bar.Inputs.Strings(); !inList(g, w) {
+ t.Errorf("bar combined jars %v does not contain %q", w, g)
+ }
+
+ if g, w := barSrcJar.Args["jarArgs"], "-C . -f a.java -f b.java -f c.java"; g != w {
+ t.Errorf("bar source jar args %q is not %q", w, g)
+ }
+
+ if g, w := barRes.Args["jarArgs"], "-C java-res -f java-res/a/a -f java-res/b/b"; g != w {
+ t.Errorf("bar resource jar args %q is not %q", w, g)
+ }
+}
+
func TestGeneratedSources(t *testing.T) {
ctx := testJava(t, `
java_library {