Merge "Soong: Add synopsis to vndk_prebuilt_shared module under cc package."
diff --git a/Android.bp b/Android.bp
index 7465341..a4e6e7d 100644
--- a/Android.bp
+++ b/Android.bp
@@ -193,6 +193,7 @@
"cc/gen_test.go",
"cc/genrule_test.go",
"cc/library_test.go",
+ "cc/proto_test.go",
"cc/test_data_test.go",
"cc/util_test.go",
],
diff --git a/android/config.go b/android/config.go
index fff77ca..84dd66f 100644
--- a/android/config.go
+++ b/android/config.go
@@ -200,12 +200,14 @@
func TestConfig(buildDir string, env map[string]string) Config {
config := &config{
productVariables: productVariables{
- DeviceName: stringPtr("test_device"),
- Platform_sdk_version: intPtr(26),
- AAPTConfig: []string{"normal", "large", "xlarge", "hdpi", "xhdpi", "xxhdpi"},
- AAPTPreferredConfig: stringPtr("xhdpi"),
- AAPTCharacteristics: stringPtr("nosdcard"),
- AAPTPrebuiltDPI: []string{"xhdpi", "xxhdpi"},
+ DeviceName: stringPtr("test_device"),
+ Platform_sdk_version: intPtr(26),
+ DeviceSystemSdkVersions: []string{"14", "15"},
+ Platform_systemsdk_versions: []string{"25", "26"},
+ AAPTConfig: []string{"normal", "large", "xlarge", "hdpi", "xhdpi", "xxhdpi"},
+ AAPTPreferredConfig: stringPtr("xhdpi"),
+ AAPTCharacteristics: stringPtr("nosdcard"),
+ AAPTPrebuiltDPI: []string{"xhdpi", "xxhdpi"},
},
buildDir: buildDir,
@@ -499,6 +501,22 @@
return String(c.productVariables.Platform_sdk_codename)
}
+func (c *config) PlatformSecurityPatch() string {
+ return String(c.productVariables.Platform_security_patch)
+}
+
+func (c *config) PlatformPreviewSdkVersion() string {
+ return String(c.productVariables.Platform_preview_sdk_version)
+}
+
+func (c *config) PlatformMinSupportedTargetSdkVersion() string {
+ return String(c.productVariables.Platform_min_supported_target_sdk_version)
+}
+
+func (c *config) PlatformBaseOS() string {
+ return String(c.productVariables.Platform_base_os)
+}
+
func (c *config) MinSupportedSdkVersion() int {
return 16
}
diff --git a/android/defs.go b/android/defs.go
index cd8b4e3..4890c66 100644
--- a/android/defs.go
+++ b/android/defs.go
@@ -20,7 +20,7 @@
)
var (
- pctx = NewPackageContext("android/soong/common")
+ pctx = NewPackageContext("android/soong/android")
cpPreserveSymlinks = pctx.VariableConfigMethod("cpPreserveSymlinks",
Config.CpPreserveSymlinksFlags)
diff --git a/android/module.go b/android/module.go
index abf2cae..201c27a 100644
--- a/android/module.go
+++ b/android/module.go
@@ -1425,6 +1425,10 @@
Srcs() Paths
}
+type HostToolProvider interface {
+ HostToolPath() OptionalPath
+}
+
// Returns a list of paths expanded from globs and modules referenced using ":module" syntax. The property must
// be tagged with `android:"path" to support automatic source module dependency resolution.
//
diff --git a/android/proto.go b/android/proto.go
index 801837e..5247c68 100644
--- a/android/proto.go
+++ b/android/proto.go
@@ -14,6 +14,13 @@
package android
+import (
+ "strings"
+
+ "github.com/google/blueprint"
+ "github.com/google/blueprint/proptools"
+)
+
// TODO(ccross): protos are often used to communicate between multiple modules. If the only
// way to convert a proto to source is to reference it as a source file, and external modules cannot
// reference source files in other modules, then every module that owns a proto file will need to
@@ -22,36 +29,72 @@
// and then external modules could depend on the proto module but use their own settings to
// generate the source.
-func ProtoFlags(ctx ModuleContext, p *ProtoProperties) []string {
- protoFlags := []string{}
+type ProtoFlags struct {
+ Flags []string
+ CanonicalPathFromRoot bool
+ Dir ModuleGenPath
+ SubDir ModuleGenPath
+ OutTypeFlag string
+ OutParams []string
+ Deps Paths
+}
+
+type protoDependencyTag struct {
+ blueprint.BaseDependencyTag
+ name string
+}
+
+var ProtoPluginDepTag = protoDependencyTag{name: "plugin"}
+
+func ProtoDeps(ctx BottomUpMutatorContext, p *ProtoProperties) {
+ if String(p.Proto.Plugin) != "" && String(p.Proto.Type) != "" {
+ ctx.ModuleErrorf("only one of proto.type and proto.plugin can be specified.")
+ }
+
+ if plugin := String(p.Proto.Plugin); plugin != "" {
+ ctx.AddFarVariationDependencies([]blueprint.Variation{
+ {Mutator: "arch", Variation: ctx.Config().BuildOsVariant},
+ }, ProtoPluginDepTag, "protoc-gen-"+plugin)
+ }
+}
+
+func GetProtoFlags(ctx ModuleContext, p *ProtoProperties) ProtoFlags {
+ var flags []string
+ var deps Paths
if len(p.Proto.Local_include_dirs) > 0 {
localProtoIncludeDirs := PathsForModuleSrc(ctx, p.Proto.Local_include_dirs)
- protoFlags = append(protoFlags, JoinWithPrefix(localProtoIncludeDirs.Strings(), "-I"))
+ flags = append(flags, JoinWithPrefix(localProtoIncludeDirs.Strings(), "-I"))
}
if len(p.Proto.Include_dirs) > 0 {
rootProtoIncludeDirs := PathsForSource(ctx, p.Proto.Include_dirs)
- protoFlags = append(protoFlags, JoinWithPrefix(rootProtoIncludeDirs.Strings(), "-I"))
+ flags = append(flags, JoinWithPrefix(rootProtoIncludeDirs.Strings(), "-I"))
}
- return protoFlags
-}
+ ctx.VisitDirectDepsWithTag(ProtoPluginDepTag, func(dep Module) {
+ if hostTool, ok := dep.(HostToolProvider); !ok || !hostTool.HostToolPath().Valid() {
+ ctx.PropertyErrorf("proto.plugin", "module %q is not a host tool provider",
+ ctx.OtherModuleName(dep))
+ } else {
+ plugin := String(p.Proto.Plugin)
+ deps = append(deps, hostTool.HostToolPath().Path())
+ flags = append(flags, "--plugin=protoc-gen-"+plugin+"="+hostTool.HostToolPath().String())
+ }
+ })
-func ProtoCanonicalPathFromRoot(ctx ModuleContext, p *ProtoProperties) bool {
- if p.Proto.Canonical_path_from_root == nil {
- return true
+ var protoOutFlag string
+ if plugin := String(p.Proto.Plugin); plugin != "" {
+ protoOutFlag = "--" + plugin + "_out"
}
- return *p.Proto.Canonical_path_from_root
-}
-// ProtoDir returns the module's "gen/proto" directory
-func ProtoDir(ctx ModuleContext) ModuleGenPath {
- return PathForModuleGen(ctx, "proto")
-}
-
-// ProtoSubDir returns the module's "gen/proto/path/to/module" directory
-func ProtoSubDir(ctx ModuleContext) ModuleGenPath {
- return PathForModuleGen(ctx, "proto", ctx.ModuleDir())
+ return ProtoFlags{
+ Flags: flags,
+ Deps: deps,
+ OutTypeFlag: protoOutFlag,
+ CanonicalPathFromRoot: proptools.BoolDefault(p.Proto.Canonical_path_from_root, true),
+ Dir: PathForModuleGen(ctx, "proto"),
+ SubDir: PathForModuleGen(ctx, "proto", ctx.ModuleDir()),
+ }
}
type ProtoProperties struct {
@@ -59,6 +102,9 @@
// Proto generator type. C++: full or lite. Java: micro, nano, stream, or lite.
Type *string `android:"arch_variant"`
+ // Proto plugin to use as the generator. Must be a cc_binary_host module.
+ Plugin *string `android:"arch_variant"`
+
// list of directories that will be added to the protoc include paths.
Include_dirs []string
@@ -76,3 +122,28 @@
Canonical_path_from_root *bool
} `android:"arch_variant"`
}
+
+func ProtoRule(ctx ModuleContext, rule *RuleBuilder, protoFile Path, flags ProtoFlags, deps Paths,
+ outDir WritablePath, depFile WritablePath, outputs WritablePaths) {
+
+ var protoBase string
+ if flags.CanonicalPathFromRoot {
+ protoBase = "."
+ } else {
+ rel := protoFile.Rel()
+ protoBase = strings.TrimSuffix(protoFile.String(), rel)
+ }
+
+ rule.Command().
+ Tool(ctx.Config().HostToolPath(ctx, "aprotoc")).
+ FlagWithArg(flags.OutTypeFlag+"=", strings.Join(flags.OutParams, ",")+":"+outDir.String()).
+ FlagWithDepFile("--dependency_out=", depFile).
+ FlagWithArg("-I ", protoBase).
+ Flags(flags.Flags).
+ Input(protoFile).
+ Implicits(deps).
+ ImplicitOutputs(outputs)
+
+ rule.Command().
+ Tool(ctx.Config().HostToolPath(ctx, "dep_fixer")).Flag(depFile.String())
+}
diff --git a/android/rule_builder.go b/android/rule_builder.go
index a2a5366..2d0fac1 100644
--- a/android/rule_builder.go
+++ b/android/rule_builder.go
@@ -171,6 +171,20 @@
return outputList
}
+// DepFiles returns the list of paths that were passed to the RuleBuilderCommand methods that take depfile paths, such
+// as RuleBuilderCommand.DepFile or RuleBuilderCommand.FlagWithDepFile.
+func (r *RuleBuilder) DepFiles() WritablePaths {
+ var depFiles WritablePaths
+
+ for _, c := range r.commands {
+ for _, depFile := range c.depFiles {
+ depFiles = append(depFiles, depFile)
+ }
+ }
+
+ return depFiles
+}
+
// Installs returns the list of tuples passed to Install.
func (r *RuleBuilder) Installs() RuleBuilderInstalls {
return append(RuleBuilderInstalls(nil), r.installs...)
@@ -222,9 +236,17 @@
var _ BuilderContext = ModuleContext(nil)
var _ BuilderContext = SingletonContext(nil)
+func (r *RuleBuilder) depFileMergerCmd(ctx PathContext, depFiles WritablePaths) *RuleBuilderCommand {
+ return (&RuleBuilderCommand{}).
+ Tool(ctx.Config().HostToolPath(ctx, "dep_fixer")).
+ Flags(depFiles.Strings())
+}
+
// Build adds the built command line to the build graph, with dependencies on Inputs and Tools, and output files for
// Outputs.
func (r *RuleBuilder) Build(pctx PackageContext, ctx BuilderContext, name string, desc string) {
+ name = ninjaNameEscape(name)
+
if len(r.missingDeps) > 0 {
ctx.Build(pctx, BuildParams{
Rule: ErrorRule,
@@ -237,16 +259,45 @@
return
}
- if len(r.Commands()) > 0 {
+ tools := r.Tools()
+ commands := r.Commands()
+
+ var depFile WritablePath
+ var depFormat blueprint.Deps
+ if depFiles := r.DepFiles(); len(depFiles) > 0 {
+ depFile = depFiles[0]
+ depFormat = blueprint.DepsGCC
+ if len(depFiles) > 1 {
+ // Add a command locally that merges all depfiles together into the first depfile.
+ cmd := r.depFileMergerCmd(ctx, depFiles)
+ commands = append(commands, string(cmd.buf))
+ tools = append(tools, cmd.tools...)
+ }
+ }
+
+ // Ninja doesn't like multiple outputs when depfiles are enabled, move all but the first output to
+ // ImplicitOutputs. RuleBuilder never uses "$out", so the distinction between Outputs and ImplicitOutputs
+ // doesn't matter.
+ var output WritablePath
+ var implicitOutputs WritablePaths
+ if outputs := r.Outputs(); len(outputs) > 0 {
+ output = outputs[0]
+ implicitOutputs = outputs[1:]
+ }
+
+ if len(commands) > 0 {
ctx.Build(pctx, BuildParams{
Rule: ctx.Rule(pctx, name, blueprint.RuleParams{
- Command: strings.Join(proptools.NinjaEscapeList(r.Commands()), " && "),
- CommandDeps: r.Tools().Strings(),
+ Command: strings.Join(proptools.NinjaEscapeList(commands), " && "),
+ CommandDeps: tools.Strings(),
Restat: r.restat,
}),
- Implicits: r.Inputs(),
- Outputs: r.Outputs(),
- Description: desc,
+ Implicits: r.Inputs(),
+ Output: output,
+ ImplicitOutputs: implicitOutputs,
+ Depfile: depFile,
+ Deps: depFormat,
+ Description: desc,
})
}
}
@@ -256,10 +307,11 @@
// RuleBuilderCommand, so they can be used chained or unchained. All methods that add text implicitly add a single
// space as a separator from the previous method.
type RuleBuilderCommand struct {
- buf []byte
- inputs Paths
- outputs WritablePaths
- tools Paths
+ buf []byte
+ inputs Paths
+ outputs WritablePaths
+ depFiles WritablePaths
+ tools Paths
}
// Text adds the specified raw text to the command line. The text should not contain input or output paths or the
@@ -284,6 +336,15 @@
return c.Text(flag)
}
+// Flags adds the specified raw text to the command line. The text should not contain input or output paths or the
+// rule will not have them listed in its dependencies or outputs.
+func (c *RuleBuilderCommand) Flags(flags []string) *RuleBuilderCommand {
+ for _, flag := range flags {
+ c.Text(flag)
+ }
+ return c
+}
+
// FlagWithArg adds the specified flag and argument text to the command line, with no separator between them. The flag
// and argument should not contain input or output paths or the rule will not have them listed in its dependencies or
// outputs.
@@ -360,6 +421,14 @@
return c
}
+// DepFile adds the specified depfile path to the paths returned by RuleBuilder.DepFiles and adds it to the command
+// line, and causes RuleBuilder.Build file to set the depfile flag for ninja. If multiple depfiles are added to
+// commands in a single RuleBuilder then RuleBuilder.Build will add an extra command to merge the depfiles together.
+func (c *RuleBuilderCommand) DepFile(path WritablePath) *RuleBuilderCommand {
+ c.depFiles = append(c.depFiles, path)
+ return c.Text(path.String())
+}
+
// ImplicitOutput adds the specified output path to the dependencies returned by RuleBuilder.Outputs without modifying
// the command line.
func (c *RuleBuilderCommand) ImplicitOutput(path WritablePath) *RuleBuilderCommand {
@@ -374,6 +443,15 @@
return c
}
+// ImplicitDepFile adds the specified depfile path to the paths returned by RuleBuilder.DepFiles without modifying
+// the command line, and causes RuleBuilder.Build file to set the depfile flag for ninja. If multiple depfiles
+// are added to commands in a single RuleBuilder then RuleBuilder.Build will add an extra command to merge the
+// depfiles together.
+func (c *RuleBuilderCommand) ImplicitDepFile(path WritablePath) *RuleBuilderCommand {
+ c.depFiles = append(c.depFiles, path)
+ return c
+}
+
// FlagWithInput adds the specified flag and input path to the command line, with no separator between them. The path
// will also be added to the dependencies returned by RuleBuilder.Inputs.
func (c *RuleBuilderCommand) FlagWithInput(flag string, path Path) *RuleBuilderCommand {
@@ -406,7 +484,35 @@
return c.Text(flag + path.String())
}
+// FlagWithDepFile adds the specified flag and depfile path to the command line, with no separator between them. The path
+// will also be added to the outputs returned by RuleBuilder.Outputs.
+func (c *RuleBuilderCommand) FlagWithDepFile(flag string, path WritablePath) *RuleBuilderCommand {
+ c.depFiles = append(c.depFiles, path)
+ return c.Text(flag + path.String())
+}
+
// String returns the command line.
func (c *RuleBuilderCommand) String() string {
return string(c.buf)
}
+
+func ninjaNameEscape(s string) string {
+ b := []byte(s)
+ escaped := false
+ for i, c := range b {
+ valid := (c >= 'a' && c <= 'z') ||
+ (c >= 'A' && c <= 'Z') ||
+ (c >= '0' && c <= '9') ||
+ (c == '_') ||
+ (c == '-') ||
+ (c == '.')
+ if !valid {
+ b[i] = '_'
+ escaped = true
+ }
+ }
+ if escaped {
+ s = string(b)
+ }
+ return s
+}
diff --git a/android/rule_builder_test.go b/android/rule_builder_test.go
index 01d23e5..7bad025 100644
--- a/android/rule_builder_test.go
+++ b/android/rule_builder_test.go
@@ -171,6 +171,14 @@
// ls -l
}
+func ExampleRuleBuilderCommand_Flags() {
+ ctx := pathContext()
+ fmt.Println(NewRuleBuilder().Command().
+ Tool(PathForSource(ctx, "ls")).Flags([]string{"-l", "-a"}))
+ // Output:
+ // ls -l -a
+}
+
func ExampleRuleBuilderCommand_FlagWithArg() {
ctx := pathContext()
fmt.Println(NewRuleBuilder().Command().
@@ -229,23 +237,27 @@
rule := NewRuleBuilder()
fs := map[string][]byte{
- "input": nil,
- "Implicit": nil,
- "Input": nil,
- "Tool": nil,
- "input2": nil,
- "tool2": nil,
- "input3": nil,
+ "dep_fixer": nil,
+ "input": nil,
+ "Implicit": nil,
+ "Input": nil,
+ "Tool": nil,
+ "input2": nil,
+ "tool2": nil,
+ "input3": nil,
}
ctx := PathContextForTesting(TestConfig("out", nil), fs)
cmd := rule.Command().
+ DepFile(PathForOutput(ctx, "DepFile")).
Flag("Flag").
FlagWithArg("FlagWithArg=", "arg").
+ FlagWithDepFile("FlagWithDepFile=", PathForOutput(ctx, "depfile")).
FlagWithInput("FlagWithInput=", PathForSource(ctx, "input")).
FlagWithOutput("FlagWithOutput=", PathForOutput(ctx, "output")).
Implicit(PathForSource(ctx, "Implicit")).
+ ImplicitDepFile(PathForOutput(ctx, "ImplicitDepFile")).
ImplicitOutput(PathForOutput(ctx, "ImplicitOutput")).
Input(PathForSource(ctx, "Input")).
Output(PathForOutput(ctx, "Output")).
@@ -254,6 +266,7 @@
rule.Command().
Text("command2").
+ DepFile(PathForOutput(ctx, "depfile2")).
Input(PathForSource(ctx, "input2")).
Output(PathForOutput(ctx, "output2")).
Tool(PathForSource(ctx, "tool2"))
@@ -271,25 +284,37 @@
Output(PathForOutput(ctx, "output3"))
wantCommands := []string{
- "Flag FlagWithArg=arg FlagWithInput=input FlagWithOutput=out/output Input out/Output Text Tool after command2 old cmd",
- "command2 input2 out/output2 tool2",
+ "out/DepFile Flag FlagWithArg=arg FlagWithDepFile=out/depfile FlagWithInput=input FlagWithOutput=out/output Input out/Output Text Tool after command2 old cmd",
+ "command2 out/depfile2 input2 out/output2 tool2",
"command3 input3 out/output2 out/output3",
}
+
+ wantDepMergerCommand := "out/host/" + ctx.Config().PrebuiltOS() + "/bin/dep_fixer out/DepFile out/depfile out/ImplicitDepFile out/depfile2"
+
wantInputs := PathsForSource(ctx, []string{"Implicit", "Input", "input", "input2", "input3"})
wantOutputs := PathsForOutput(ctx, []string{"ImplicitOutput", "Output", "output", "output2", "output3"})
+ wantDepFiles := PathsForOutput(ctx, []string{"DepFile", "depfile", "ImplicitDepFile", "depfile2"})
wantTools := PathsForSource(ctx, []string{"Tool", "tool2"})
- if !reflect.DeepEqual(rule.Commands(), wantCommands) {
- t.Errorf("\nwant rule.Commands() = %#v\n got %#v", wantCommands, rule.Commands())
+ if g, w := rule.Commands(), wantCommands; !reflect.DeepEqual(g, w) {
+ t.Errorf("\nwant rule.Commands() = %#v\n got %#v", w, g)
}
- if !reflect.DeepEqual(rule.Inputs(), wantInputs) {
- t.Errorf("\nwant rule.Inputs() = %#v\n got %#v", wantInputs, rule.Inputs())
+
+ if g, w := rule.depFileMergerCmd(ctx, rule.DepFiles()).String(), wantDepMergerCommand; g != w {
+ t.Errorf("\nwant rule.depFileMergerCmd() = %#v\n got %#v", w, g)
}
- if !reflect.DeepEqual(rule.Outputs(), wantOutputs) {
- t.Errorf("\nwant rule.Outputs() = %#v\n got %#v", wantOutputs, rule.Outputs())
+
+ if g, w := rule.Inputs(), wantInputs; !reflect.DeepEqual(w, g) {
+ t.Errorf("\nwant rule.Inputs() = %#v\n got %#v", w, g)
}
- if !reflect.DeepEqual(rule.Tools(), wantTools) {
- t.Errorf("\nwant rule.Tools() = %#v\n got %#v", wantTools, rule.Tools())
+ if g, w := rule.Outputs(), wantOutputs; !reflect.DeepEqual(w, g) {
+ t.Errorf("\nwant rule.Outputs() = %#v\n got %#v", w, g)
+ }
+ if g, w := rule.DepFiles(), wantDepFiles; !reflect.DeepEqual(w, g) {
+ t.Errorf("\nwant rule.DepFiles() = %#v\n got %#v", w, g)
+ }
+ if g, w := rule.Tools(), wantTools; !reflect.DeepEqual(w, g) {
+ t.Errorf("\nwant rule.Tools() = %#v\n got %#v", w, g)
}
}
@@ -375,8 +400,8 @@
t.Errorf("want Implicits = [%q], got %q", "bar", params.Implicits.Strings())
}
- if len(params.Outputs) != 1 || params.Outputs[0].String() != wantOutput {
- t.Errorf("want Outputs = [%q], got %q", wantOutput, params.Outputs.Strings())
+ if params.Output.String() != wantOutput {
+ t.Errorf("want Output = %q, got %q", wantOutput, params.Output)
}
if !params.RuleParams.Restat {
diff --git a/android/testing.go b/android/testing.go
index 7f443a3..0ec5af5 100644
--- a/android/testing.go
+++ b/android/testing.go
@@ -196,6 +196,7 @@
var searchedOutputs []string
for _, p := range provider.BuildParamsForTests() {
outputs := append(WritablePaths(nil), p.Outputs...)
+ outputs = append(outputs, p.ImplicitOutputs...)
if p.Output != nil {
outputs = append(outputs, p.Output)
}
@@ -222,6 +223,7 @@
var outputFullPaths []string
for _, p := range provider.BuildParamsForTests() {
outputs := append(WritablePaths(nil), p.Outputs...)
+ outputs = append(outputs, p.ImplicitOutputs...)
if p.Output != nil {
outputs = append(outputs, p.Output)
}
diff --git a/android/variable.go b/android/variable.go
index aa8c804..21af31f 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -43,7 +43,8 @@
} `android:"arch_variant"`
Malloc_not_svelte struct {
- Cflags []string `android:"arch_variant"`
+ Cflags []string `android:"arch_variant"`
+ Shared_libs []string `android:"arch_variant"`
} `android:"arch_variant"`
Safestack struct {
@@ -136,14 +137,18 @@
BuildNumberFromFile *string `json:",omitempty"`
DateFromFile *string `json:",omitempty"`
- Platform_version_name *string `json:",omitempty"`
- Platform_sdk_version *int `json:",omitempty"`
- Platform_sdk_codename *string `json:",omitempty"`
- Platform_sdk_final *bool `json:",omitempty"`
- Platform_version_active_codenames []string `json:",omitempty"`
- Platform_version_future_codenames []string `json:",omitempty"`
- Platform_vndk_version *string `json:",omitempty"`
- Platform_systemsdk_versions []string `json:",omitempty"`
+ Platform_version_name *string `json:",omitempty"`
+ Platform_sdk_version *int `json:",omitempty"`
+ Platform_sdk_codename *string `json:",omitempty"`
+ Platform_sdk_final *bool `json:",omitempty"`
+ Platform_version_active_codenames []string `json:",omitempty"`
+ Platform_version_future_codenames []string `json:",omitempty"`
+ Platform_vndk_version *string `json:",omitempty"`
+ Platform_systemsdk_versions []string `json:",omitempty"`
+ Platform_security_patch *string `json:",omitempty"`
+ Platform_preview_sdk_version *string `json:",omitempty"`
+ Platform_min_supported_target_sdk_version *string `json:",omitempty"`
+ Platform_base_os *string `json:",omitempty"`
DeviceName *string `json:",omitempty"`
DeviceArch *string `json:",omitempty"`
diff --git a/apex/apex.go b/apex/apex.go
index e07fae0..3327a56 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -119,7 +119,7 @@
)
func init() {
- pctx.Import("android/soong/common")
+ pctx.Import("android/soong/android")
pctx.Import("android/soong/java")
pctx.HostBinToolVariable("apexer", "apexer")
// ART minimal builds (using the master-art manifest) do not have the "frameworks/base"
@@ -396,9 +396,8 @@
outputFiles map[apexPackaging]android.WritablePath
installDir android.OutputPath
- public_key_file android.Path
- private_key_file android.Path
- bundle_public_key bool
+ public_key_file android.Path
+ private_key_file android.Path
container_certificate_file android.Path
container_private_key_file android.Path
@@ -746,10 +745,6 @@
if key, ok := child.(*apexKey); ok {
a.private_key_file = key.private_key_file
a.public_key_file = key.public_key_file
- // If the key is not installed, bundled it with the APEX.
- // Note: this bundled key is valid only for non-production builds
- // (eng/userdebug).
- a.bundle_public_key = !key.installable() && ctx.Config().Debuggable()
return false
} else {
ctx.PropertyErrorf("key", "%q is not an apex_key module", depName)
@@ -968,11 +963,8 @@
optFlags := []string{}
// Additional implicit inputs.
- implicitInputs = append(implicitInputs, cannedFsConfig, fileContexts, a.private_key_file)
- if a.bundle_public_key {
- implicitInputs = append(implicitInputs, a.public_key_file)
- optFlags = append(optFlags, "--pubkey "+a.public_key_file.String())
- }
+ implicitInputs = append(implicitInputs, cannedFsConfig, fileContexts, a.private_key_file, a.public_key_file)
+ optFlags = append(optFlags, "--pubkey "+a.public_key_file.String())
manifestPackageName, overridden := ctx.DeviceConfig().OverrideManifestPackageNameFor(ctx.ModuleName())
if overridden {
@@ -1057,7 +1049,7 @@
func (a *apexBundle) buildFlattenedApex(ctx android.ModuleContext) {
if a.installable() {
- // For flattened APEX, do nothing but make sure that apex_manifest.json file is also copied along
+ // For flattened APEX, do nothing but make sure that apex_manifest.json and apex_pubkey are also copied along
// with other ordinary files.
manifest := android.PathForModuleSrc(ctx, proptools.StringDefault(a.properties.Manifest, "apex_manifest.json"))
@@ -1070,6 +1062,15 @@
})
a.filesInfo = append(a.filesInfo, apexFile{copiedManifest, ctx.ModuleName() + ".apex_manifest.json", ".", etc, nil, nil})
+ // rename to apex_pubkey
+ copiedPubkey := android.PathForModuleOut(ctx, "apex_pubkey")
+ ctx.Build(pctx, android.BuildParams{
+ Rule: android.Cp,
+ Input: a.public_key_file,
+ Output: copiedPubkey,
+ })
+ a.filesInfo = append(a.filesInfo, apexFile{copiedPubkey, ctx.ModuleName() + ".apex_pubkey", ".", etc, nil, nil})
+
if ctx.Config().FlattenApex() {
for _, fi := range a.filesInfo {
dir := filepath.Join("apex", ctx.ModuleName(), fi.installDir)
@@ -1215,7 +1216,6 @@
fmt.Fprintln(w, "LOCAL_MODULE_PATH :=", filepath.Join("$(OUT_DIR)", a.installDir.RelPathString()))
fmt.Fprintln(w, "LOCAL_MODULE_STEM :=", name+apexType.suffix())
fmt.Fprintln(w, "LOCAL_UNINSTALLABLE_MODULE :=", !a.installable())
- fmt.Fprintln(w, "LOCAL_REQUIRED_MODULES :=", String(a.properties.Key))
if a.installable() && a.mergedNoticeFile != nil {
fmt.Fprintln(w, "LOCAL_NOTICE_FILE :=", a.mergedNoticeFile.String())
}
@@ -1317,18 +1317,9 @@
Src *string
}
}
-
- // the name of the apex_key module that contains the matching public key to be installed.
- Key *string
}
func (p *Prebuilt) DepsMutator(ctx android.BottomUpMutatorContext) {
- if String(p.properties.Key) == "" {
- ctx.ModuleErrorf("key is missing")
- return
- }
- ctx.AddDependency(ctx.Module(), keyTag, *p.properties.Key)
-
// This is called before prebuilt_select and prebuilt_postdeps mutators
// The mutators requires that src to be set correctly for each arch so that
// arch variants are disabled when src is not provided for the arch.
@@ -1380,7 +1371,6 @@
func(w io.Writer, outputFile android.Path) {
fmt.Fprintln(w, "LOCAL_MODULE_PATH :=", filepath.Join("$(OUT_DIR)", p.installDir.RelPathString()))
fmt.Fprintln(w, "LOCAL_MODULE_STEM :=", p.BaseModuleName()+imageApexSuffix)
- fmt.Fprintln(w, "LOCAL_REQUIRED_MODULES :=", String(p.properties.Key))
},
},
}
diff --git a/apex/apex_test.go b/apex/apex_test.go
index 1e8d5b4..6d101d8 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -15,8 +15,6 @@
package apex
import (
- "bufio"
- "bytes"
"io/ioutil"
"os"
"strings"
@@ -299,6 +297,10 @@
`)
apexRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexRule")
+
+ optFlags := apexRule.Args["opt_flags"]
+ ensureContains(t, optFlags, "--pubkey vendor/foo/devkeys/testkey.avbpubkey")
+
copyCmds := apexRule.Args["copy_commands"]
// Ensure that main rule creates an output
@@ -1197,14 +1199,6 @@
if actual != expected {
t.Errorf("wrong install path. expected %q. actual %q", expected, actual)
}
-
- apex_key := ctx.ModuleForTests("myapex.key", "android_common").Module().(*apexKey)
- expected = "target/product/test_device/product/etc/security/apex"
- actual = apex_key.installDir.RelPathString()
- if actual != expected {
- t.Errorf("wrong install path. expected %q. actual %q", expected, actual)
- }
-
}
func TestApexKeyFromOtherModule(t *testing.T) {
@@ -1252,14 +1246,6 @@
src: "myapex-arm.apex",
},
},
- key: "myapex.key"
- }
-
- apex_key {
- name: "myapex.key",
- public_key: "testkey.avbpubkey",
- private_key: "testkey.pem",
- product_specific: true,
}
`)
@@ -1269,24 +1255,4 @@
if prebuilt.inputApex.String() != expectedInput {
t.Errorf("inputApex invalid. expected: %q, actual: %q", expectedInput, prebuilt.inputApex.String())
}
-
- // Check if the key module is added as a required module.
- buf := &bytes.Buffer{}
- prebuilt.AndroidMk().Extra[0](buf, nil)
- found := false
- scanner := bufio.NewScanner(bytes.NewReader(buf.Bytes()))
- expected := "myapex.key"
- for scanner.Scan() {
- line := scanner.Text()
- tok := strings.Split(line, " := ")
- if tok[0] == "LOCAL_REQUIRED_MODULES" {
- found = true
- if tok[1] != "myapex.key" {
- t.Errorf("Unexpected LOCAL_REQUIRED_MODULES '%s', expected '%s'", tok[1], expected)
- }
- }
- }
- if !found {
- t.Errorf("Couldn't find a LOCAL_REQUIRED_MODULES entry")
- }
}
diff --git a/apex/key.go b/apex/key.go
index fbd29bc..a627e4b 100644
--- a/apex/key.go
+++ b/apex/key.go
@@ -16,8 +16,6 @@
import (
"fmt"
- "io"
- "path/filepath"
"strings"
"android/soong/android"
@@ -39,7 +37,6 @@
public_key_file android.Path
private_key_file android.Path
- installDir android.OutputPath
keyName string
}
@@ -64,7 +61,7 @@
}
func (m *apexKey) installable() bool {
- return m.properties.Installable == nil || proptools.Bool(m.properties.Installable)
+ return false
}
func (m *apexKey) GenerateAndroidBuildActions(ctx android.ModuleContext) {
@@ -99,25 +96,6 @@
return
}
m.keyName = pubKeyName
-
- m.installDir = android.PathForModuleInstall(ctx, "etc/security/apex")
- if m.installable() {
- ctx.InstallFile(m.installDir, m.keyName, m.public_key_file)
- }
-}
-
-func (m *apexKey) AndroidMk() android.AndroidMkData {
- return android.AndroidMkData{
- Class: "ETC",
- OutputFile: android.OptionalPathForPath(m.public_key_file),
- Extra: []android.AndroidMkExtraFunc{
- func(w io.Writer, outputFile android.Path) {
- fmt.Fprintln(w, "LOCAL_MODULE_PATH :=", filepath.Join("$(OUT_DIR)", m.installDir.RelPathString()))
- fmt.Fprintln(w, "LOCAL_INSTALLED_MODULE_STEM :=", m.keyName)
- fmt.Fprintln(w, "LOCAL_UNINSTALLABLE_MODULE :=", !m.installable())
- },
- },
- }
}
////////////////////////////////////////////////////////////////////////
diff --git a/cc/binary.go b/cc/binary.go
index 51e68fc..35c3d85 100644
--- a/cc/binary.go
+++ b/cc/binary.go
@@ -384,7 +384,7 @@
TransformObjToDynamicBinary(ctx, objs.objFiles, sharedLibs, deps.StaticLibs,
deps.LateStaticLibs, deps.WholeStaticLibs, linkerDeps, deps.CrtBegin, deps.CrtEnd, true,
- builderFlags, outputFile, nil)
+ builderFlags, outputFile)
objs.coverageFiles = append(objs.coverageFiles, deps.StaticLibObjs.coverageFiles...)
objs.coverageFiles = append(objs.coverageFiles, deps.WholeStaticLibObjs.coverageFiles...)
diff --git a/cc/builder.go b/cc/builder.go
index 6dd7c05..c64243f 100644
--- a/cc/builder.go
+++ b/cc/builder.go
@@ -26,7 +26,6 @@
"strings"
"github.com/google/blueprint"
- "github.com/google/blueprint/pathtools"
"android/soong/android"
"android/soong/cc/config"
@@ -260,13 +259,9 @@
stripAddGnuDebuglink bool
stripUseGnuStrip bool
- protoDeps android.Paths
- protoFlags string
- protoOutTypeFlag string
- protoOutParams string
+ proto android.ProtoFlags
protoC bool
protoOptionsFile bool
- protoRoot bool
}
type Objects struct {
@@ -600,7 +595,7 @@
// and shared libraries, to a shared library (.so) or dynamic executable
func TransformObjToDynamicBinary(ctx android.ModuleContext,
objFiles, sharedLibs, staticLibs, lateStaticLibs, wholeStaticLibs, deps android.Paths,
- crtBegin, crtEnd android.OptionalPath, groupLate bool, flags builderFlags, outputFile android.WritablePath, implicitOutputs android.WritablePaths) {
+ crtBegin, crtEnd android.OptionalPath, groupLate bool, flags builderFlags, outputFile android.WritablePath) {
ldCmd := "${config.ClangBin}/clang++"
@@ -637,11 +632,7 @@
}
for _, lib := range sharedLibs {
- libFile := lib.String()
- if ctx.Windows() {
- libFile = pathtools.ReplaceExtension(libFile, "a")
- }
- libFlagsList = append(libFlagsList, libFile)
+ libFlagsList = append(libFlagsList, lib.String())
}
deps = append(deps, staticLibs...)
@@ -652,12 +643,11 @@
}
ctx.Build(pctx, android.BuildParams{
- Rule: ld,
- Description: "link " + outputFile.Base(),
- Output: outputFile,
- ImplicitOutputs: implicitOutputs,
- Inputs: objFiles,
- Implicits: deps,
+ Rule: ld,
+ Description: "link " + outputFile.Base(),
+ Output: outputFile,
+ Inputs: objFiles,
+ Implicits: deps,
Args: map[string]string{
"ldCmd": ldCmd,
"crtBegin": crtBegin.String(),
diff --git a/cc/cc.go b/cc/cc.go
index f5a1567..0668fd9 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -162,13 +162,9 @@
GroupStaticLibs bool
- protoDeps android.Paths
- protoFlags []string // Flags that apply to proto source files
- protoOutTypeFlag string // The output type, --cpp_out for example
- protoOutParams []string // Flags that modify the output of proto generated files
- protoC bool // Whether to use C instead of C++
- protoOptionsFile bool // Whether to look for a .options file next to the .proto
- ProtoRoot bool
+ proto android.ProtoFlags
+ protoC bool // Whether to use C instead of C++
+ protoOptionsFile bool // Whether to look for a .options file next to the .proto
}
type ObjectLinkerProperties struct {
@@ -1597,6 +1593,10 @@
return
}
+ if depTag == android.ProtoPluginDepTag {
+ return
+ }
+
if dep.Target().Os != ctx.Os() {
ctx.ModuleErrorf("OS mismatch between %q and %q", ctx.ModuleName(), depName)
return
diff --git a/cc/cc_test.go b/cc/cc_test.go
index 8c0bcfe..05d74b9 100644
--- a/cc/cc_test.go
+++ b/cc/cc_test.go
@@ -54,6 +54,7 @@
func createTestContext(t *testing.T, config android.Config, bp string, os android.OsType) *android.TestContext {
ctx := android.NewTestArchContext()
ctx.RegisterModuleType("cc_binary", android.ModuleFactoryAdaptor(BinaryFactory))
+ ctx.RegisterModuleType("cc_binary_host", android.ModuleFactoryAdaptor(binaryHostFactory))
ctx.RegisterModuleType("cc_library", android.ModuleFactoryAdaptor(LibraryFactory))
ctx.RegisterModuleType("cc_library_shared", android.ModuleFactoryAdaptor(LibrarySharedFactory))
ctx.RegisterModuleType("cc_library_static", android.ModuleFactoryAdaptor(LibraryStaticFactory))
diff --git a/cc/compiler.go b/cc/compiler.go
index fe46a3c..f9af4d8 100644
--- a/cc/compiler.go
+++ b/cc/compiler.go
@@ -221,6 +221,7 @@
deps.GeneratedSources = append(deps.GeneratedSources, compiler.Properties.Generated_sources...)
deps.GeneratedHeaders = append(deps.GeneratedHeaders, compiler.Properties.Generated_headers...)
+ android.ProtoDeps(ctx, &compiler.Proto)
if compiler.hasSrcExt(".proto") {
deps = protoDeps(ctx, deps, &compiler.Proto, Bool(compiler.Properties.Proto.Static))
}
diff --git a/cc/config/vndk.go b/cc/config/vndk.go
index 542f737..e754ad5 100644
--- a/cc/config/vndk.go
+++ b/cc/config/vndk.go
@@ -65,6 +65,7 @@
"android.hardware.neuralnetworks@1.0",
"android.hardware.neuralnetworks@1.1",
"android.hardware.neuralnetworks@1.2",
+ "android.hardware.nfc@1.0",
"android.hardware.nfc@1.1",
"android.hardware.nfc@1.2",
"android.hardware.oemlock@1.0",
@@ -110,8 +111,11 @@
"libdumpstateutil",
"libexpat",
"libfmq",
+ "libgatekeeper",
"libgui",
"libhidlcache",
+ "libkeymaster_messages",
+ "libkeymaster_portable",
"libmedia_helper",
"libmedia_omx",
"libmemtrack",
@@ -122,7 +126,9 @@
"libsoftkeymasterdevice",
"libsqlite",
"libssl",
+ "libstagefright_amrnb_common",
"libstagefright_bufferqueue_helper",
+ "libstagefright_enc_common",
"libstagefright_flacdec",
"libstagefright_foundation",
"libstagefright_omx",
@@ -150,8 +156,10 @@
"libstagefright_soft_vpxenc",
"libstagefright_xmlparser",
"libsysutils",
+ "libtinyxml2",
"libui",
"libvorbisidec",
"libxml2",
+ "libyuv",
"libziparchive",
}
diff --git a/cc/library.go b/cc/library.go
index cab75ac..cf20747 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -357,10 +357,9 @@
)
}
} else {
- f = append(f, "-shared")
- if !ctx.Windows() {
- f = append(f, "-Wl,-soname,"+libName+flags.Toolchain.ShlibSuffix())
- }
+ f = append(f,
+ "-shared",
+ "-Wl,-soname,"+libName+flags.Toolchain.ShlibSuffix())
}
flags.LdFlags = append(f, flags.LdFlags...)
@@ -684,14 +683,6 @@
outputFile := android.PathForModuleOut(ctx, fileName)
ret := outputFile
- var implicitOutputs android.WritablePaths
- if ctx.Windows() {
- importLibraryPath := android.PathForModuleOut(ctx, pathtools.ReplaceExtension(fileName, "a"))
-
- flags.LdFlags = append(flags.LdFlags, "-Wl,--out-implib="+importLibraryPath.String())
- implicitOutputs = append(implicitOutputs, importLibraryPath)
- }
-
builderFlags := flagsToBuilderFlags(flags)
// Optimize out relinking against shared libraries whose interface hasn't changed by
@@ -743,7 +734,7 @@
TransformObjToDynamicBinary(ctx, objs.objFiles, sharedLibs,
deps.StaticLibs, deps.LateStaticLibs, deps.WholeStaticLibs,
- linkerDeps, deps.CrtBegin, deps.CrtEnd, false, builderFlags, outputFile, implicitOutputs)
+ linkerDeps, deps.CrtBegin, deps.CrtEnd, false, builderFlags, outputFile)
objs.coverageFiles = append(objs.coverageFiles, deps.StaticLibObjs.coverageFiles...)
objs.coverageFiles = append(objs.coverageFiles, deps.WholeStaticLibObjs.coverageFiles...)
@@ -848,10 +839,10 @@
if Bool(library.Properties.Proto.Export_proto_headers) {
if library.baseCompiler.hasSrcExt(".proto") {
includes := []string{}
- if flags.ProtoRoot {
- includes = append(includes, "-I"+android.ProtoSubDir(ctx).String())
+ if flags.proto.CanonicalPathFromRoot {
+ includes = append(includes, "-I"+flags.proto.SubDir.String())
}
- includes = append(includes, "-I"+android.ProtoDir(ctx).String())
+ includes = append(includes, "-I"+flags.proto.Dir.String())
library.reexportFlags(includes)
library.reuseExportedFlags = append(library.reuseExportedFlags, includes...)
library.reexportDeps(library.baseCompiler.pathDeps) // TODO: restrict to proto deps
diff --git a/cc/linker.go b/cc/linker.go
index 179a998..b279c06 100644
--- a/cc/linker.go
+++ b/cc/linker.go
@@ -255,6 +255,17 @@
}
}
+ if inList("libc_scudo", deps.SharedLibs) {
+ // libc_scudo is an alternate implementation of all
+ // allocation functions (malloc, free), that uses
+ // the scudo allocator instead of the default native
+ // allocator. If this library is in the list, make
+ // sure it's first so it properly overrides the
+ // allocation functions of all other shared libraries.
+ _, deps.SharedLibs = removeFromList("libc_scudo", deps.SharedLibs)
+ deps.SharedLibs = append([]string{"libc_scudo"}, deps.SharedLibs...)
+ }
+
// If libc and libdl are both in system_shared_libs make sure libdl comes after libc
// to avoid loading libdl before libc.
if inList("libdl", systemSharedLibs) && inList("libc", systemSharedLibs) &&
@@ -290,6 +301,10 @@
if ctx.Darwin() {
return false
}
+ // http://b/110800681 - lld cannot link Android's Windows modules yet.
+ if ctx.Windows() {
+ return false
+ }
if linker.Properties.Use_clang_lld != nil {
return Bool(linker.Properties.Use_clang_lld)
}
@@ -343,7 +358,7 @@
// darwin defaults to treating undefined symbols as errors
flags.LdFlags = append(flags.LdFlags, "-Wl,-undefined,dynamic_lookup")
}
- } else if !ctx.Darwin() && !ctx.Windows() {
+ } else if !ctx.Darwin() {
flags.LdFlags = append(flags.LdFlags, "-Wl,--no-undefined")
}
@@ -380,7 +395,7 @@
flags.LdFlags = append(flags.LdFlags, proptools.NinjaAndShellEscapeList(linker.Properties.Ldflags)...)
- if ctx.Host() && !ctx.Windows() {
+ if ctx.Host() {
rpath_prefix := `\$$ORIGIN/`
if ctx.Darwin() {
rpath_prefix = "@loader_path/"
diff --git a/cc/ndk_sysroot.go b/cc/ndk_sysroot.go
index 9265bff..e39bae5 100644
--- a/cc/ndk_sysroot.go
+++ b/cc/ndk_sysroot.go
@@ -63,7 +63,7 @@
android.RegisterModuleType("preprocessed_ndk_headers", preprocessedNdkHeadersFactory)
android.RegisterSingletonType("ndk", NdkSingleton)
- pctx.Import("android/soong/common")
+ pctx.Import("android/soong/android")
}
func getNdkInstallBase(ctx android.PathContext) android.OutputPath {
diff --git a/cc/prebuilt.go b/cc/prebuilt.go
index 966ec36..5ffeb32 100644
--- a/cc/prebuilt.go
+++ b/cc/prebuilt.go
@@ -29,16 +29,20 @@
prebuilt() *android.Prebuilt
}
+type prebuiltLinkerProperties struct {
+
+ // a prebuilt library or binary. Can reference a genrule module that generates an executable file.
+ Srcs []string `android:"path,arch_variant"`
+
+ // Check the prebuilt ELF files (e.g. DT_SONAME, DT_NEEDED, resolution of undefined
+ // symbols, etc), default true.
+ Check_elf_files *bool
+}
+
type prebuiltLinker struct {
android.Prebuilt
- properties struct {
- Srcs []string `android:"path,arch_variant"`
-
- // Check the prebuilt ELF files (e.g. DT_SONAME, DT_NEEDED, resolution of undefined
- // symbols, etc), default true.
- Check_elf_files *bool
- }
+ properties prebuiltLinkerProperties
}
func (p *prebuiltLinker) prebuilt() *android.Prebuilt {
@@ -112,6 +116,8 @@
return false
}
+// cc_prebuilt_library_shared installs a precompiled shared library that are
+// listed in the srcs property in the device's directory.
func prebuiltSharedLibraryFactory() android.Module {
module, _ := NewPrebuiltSharedLibrary(android.HostAndDeviceSupported)
return module.Init()
@@ -137,6 +143,8 @@
return module, library
}
+// cc_prebuilt_library_static installs a precompiled static library that are
+// listed in the srcs property in the device's directory.
func prebuiltStaticLibraryFactory() android.Module {
module, _ := NewPrebuiltStaticLibrary(android.HostAndDeviceSupported)
return module.Init()
@@ -197,6 +205,8 @@
return nil
}
+// cc_prebuilt_binary installs a precompiled executable in srcs property in the
+// device's directory.
func prebuiltBinaryFactory() android.Module {
module, _ := NewPrebuiltBinary(android.HostAndDeviceSupported)
return module.Init()
diff --git a/cc/proto.go b/cc/proto.go
index ce8a30e..f818edc 100644
--- a/cc/proto.go
+++ b/cc/proto.go
@@ -15,126 +15,99 @@
package cc
import (
- "strings"
-
- "github.com/google/blueprint"
"github.com/google/blueprint/pathtools"
"android/soong/android"
)
-func init() {
- pctx.HostBinToolVariable("protocCmd", "aprotoc")
- pctx.HostBinToolVariable("depFixCmd", "dep_fixer")
-}
-
-var (
- proto = pctx.AndroidStaticRule("protoc",
- blueprint.RuleParams{
- Command: "$protocCmd $protoOut=$protoOutParams:$outDir --dependency_out=$out.d -I $protoBase $protoFlags $in && " +
- `$depFixCmd $out.d`,
- CommandDeps: []string{"$protocCmd", "$depFixCmd"},
- Depfile: "${out}.d",
- Deps: blueprint.DepsGCC,
- }, "protoFlags", "protoOut", "protoOutParams", "protoBase", "outDir")
-)
-
// genProto creates a rule to convert a .proto file to generated .pb.cc and .pb.h files and returns
// the paths to the generated files.
-func genProto(ctx android.ModuleContext, protoFile android.Path, flags builderFlags) (ccFile, headerFile android.WritablePath) {
+func genProto(ctx android.ModuleContext, protoFile android.Path, flags builderFlags) (cc, header android.WritablePath) {
+ var ccFile, headerFile android.ModuleGenPath
srcSuffix := ".cc"
if flags.protoC {
srcSuffix = ".c"
}
- var protoBase string
- if flags.protoRoot {
- protoBase = "."
+ if flags.proto.CanonicalPathFromRoot {
ccFile = android.GenPathWithExt(ctx, "proto", protoFile, "pb"+srcSuffix)
headerFile = android.GenPathWithExt(ctx, "proto", protoFile, "pb.h")
} else {
rel := protoFile.Rel()
- protoBase = strings.TrimSuffix(protoFile.String(), rel)
ccFile = android.PathForModuleGen(ctx, "proto", pathtools.ReplaceExtension(rel, "pb"+srcSuffix))
headerFile = android.PathForModuleGen(ctx, "proto", pathtools.ReplaceExtension(rel, "pb.h"))
}
- protoDeps := flags.protoDeps
+ protoDeps := flags.proto.Deps
if flags.protoOptionsFile {
optionsFile := pathtools.ReplaceExtension(protoFile.String(), "options")
- optionsPath := android.ExistentPathForSource(ctx, optionsFile)
- if optionsPath.Valid() {
- protoDeps = append(android.Paths{optionsPath.Path()}, protoDeps...)
- }
+ optionsPath := android.PathForSource(ctx, optionsFile)
+ protoDeps = append(android.Paths{optionsPath}, protoDeps...)
}
- ctx.Build(pctx, android.BuildParams{
- Rule: proto,
- Description: "protoc " + protoFile.Rel(),
- Output: ccFile,
- ImplicitOutput: headerFile,
- Input: protoFile,
- Implicits: protoDeps,
- Args: map[string]string{
- "outDir": android.ProtoDir(ctx).String(),
- "protoFlags": flags.protoFlags,
- "protoOut": flags.protoOutTypeFlag,
- "protoOutParams": flags.protoOutParams,
- "protoBase": protoBase,
- },
- })
+ outDir := flags.proto.Dir
+ depFile := ccFile.ReplaceExtension(ctx, "d")
+ outputs := android.WritablePaths{ccFile, headerFile}
+
+ rule := android.NewRuleBuilder()
+
+ android.ProtoRule(ctx, rule, protoFile, flags.proto, protoDeps, outDir, depFile, outputs)
+
+ rule.Build(pctx, ctx, "protoc_"+protoFile.Rel(), "protoc "+protoFile.Rel())
return ccFile, headerFile
}
-func protoDeps(ctx BaseModuleContext, deps Deps, p *android.ProtoProperties, static bool) Deps {
+func protoDeps(ctx DepsContext, deps Deps, p *android.ProtoProperties, static bool) Deps {
var lib string
- switch String(p.Proto.Type) {
- case "full":
- if ctx.useSdk() {
- lib = "libprotobuf-cpp-full-ndk"
+ if String(p.Proto.Plugin) == "" {
+ switch String(p.Proto.Type) {
+ case "full":
+ if ctx.useSdk() {
+ lib = "libprotobuf-cpp-full-ndk"
+ static = true
+ } else {
+ lib = "libprotobuf-cpp-full"
+ }
+ case "lite", "":
+ if ctx.useSdk() {
+ lib = "libprotobuf-cpp-lite-ndk"
+ static = true
+ } else {
+ lib = "libprotobuf-cpp-lite"
+ }
+ case "nanopb-c":
+ lib = "libprotobuf-c-nano"
static = true
- } else {
- lib = "libprotobuf-cpp-full"
- }
- case "lite", "":
- if ctx.useSdk() {
- lib = "libprotobuf-cpp-lite-ndk"
+ case "nanopb-c-enable_malloc":
+ lib = "libprotobuf-c-nano-enable_malloc"
static = true
- } else {
- lib = "libprotobuf-cpp-lite"
+ case "nanopb-c-16bit":
+ lib = "libprotobuf-c-nano-16bit"
+ static = true
+ case "nanopb-c-enable_malloc-16bit":
+ lib = "libprotobuf-c-nano-enable_malloc-16bit"
+ static = true
+ case "nanopb-c-32bit":
+ lib = "libprotobuf-c-nano-32bit"
+ static = true
+ case "nanopb-c-enable_malloc-32bit":
+ lib = "libprotobuf-c-nano-enable_malloc-32bit"
+ static = true
+ default:
+ ctx.PropertyErrorf("proto.type", "unknown proto type %q",
+ String(p.Proto.Type))
}
- case "nanopb-c":
- lib = "libprotobuf-c-nano"
- static = true
- case "nanopb-c-enable_malloc":
- lib = "libprotobuf-c-nano-enable_malloc"
- static = true
- case "nanopb-c-16bit":
- lib = "libprotobuf-c-nano-16bit"
- static = true
- case "nanopb-c-enable_malloc-16bit":
- lib = "libprotobuf-c-nano-enable_malloc-16bit"
- static = true
- case "nanopb-c-32bit":
- lib = "libprotobuf-c-nano-32bit"
- static = true
- case "nanopb-c-enable_malloc-32bit":
- lib = "libprotobuf-c-nano-enable_malloc-32bit"
- static = true
- default:
- ctx.PropertyErrorf("proto.type", "unknown proto type %q",
- String(p.Proto.Type))
- }
- if static {
- deps.StaticLibs = append(deps.StaticLibs, lib)
- deps.ReexportStaticLibHeaders = append(deps.ReexportStaticLibHeaders, lib)
- } else {
- deps.SharedLibs = append(deps.SharedLibs, lib)
- deps.ReexportSharedLibHeaders = append(deps.ReexportSharedLibHeaders, lib)
+ if static {
+ deps.StaticLibs = append(deps.StaticLibs, lib)
+ deps.ReexportStaticLibHeaders = append(deps.ReexportStaticLibHeaders, lib)
+ } else {
+ deps.SharedLibs = append(deps.SharedLibs, lib)
+ deps.ReexportSharedLibHeaders = append(deps.ReexportSharedLibHeaders, lib)
+ }
}
return deps
@@ -143,41 +116,41 @@
func protoFlags(ctx ModuleContext, flags Flags, p *android.ProtoProperties) Flags {
flags.CFlags = append(flags.CFlags, "-DGOOGLE_PROTOBUF_NO_RTTI")
- flags.ProtoRoot = android.ProtoCanonicalPathFromRoot(ctx, p)
- if flags.ProtoRoot {
- flags.GlobalFlags = append(flags.GlobalFlags, "-I"+android.ProtoSubDir(ctx).String())
+ flags.proto = android.GetProtoFlags(ctx, p)
+ if flags.proto.CanonicalPathFromRoot {
+ flags.GlobalFlags = append(flags.GlobalFlags, "-I"+flags.proto.SubDir.String())
}
- flags.GlobalFlags = append(flags.GlobalFlags, "-I"+android.ProtoDir(ctx).String())
+ flags.GlobalFlags = append(flags.GlobalFlags, "-I"+flags.proto.Dir.String())
- flags.protoFlags = android.ProtoFlags(ctx, p)
+ if String(p.Proto.Plugin) == "" {
+ var plugin string
- var plugin string
+ switch String(p.Proto.Type) {
+ case "nanopb-c", "nanopb-c-enable_malloc", "nanopb-c-16bit", "nanopb-c-enable_malloc-16bit", "nanopb-c-32bit", "nanopb-c-enable_malloc-32bit":
+ flags.protoC = true
+ flags.protoOptionsFile = true
+ flags.proto.OutTypeFlag = "--nanopb_out"
+ plugin = "protoc-gen-nanopb"
+ case "full":
+ flags.proto.OutTypeFlag = "--cpp_out"
+ case "lite":
+ flags.proto.OutTypeFlag = "--cpp_out"
+ flags.proto.OutParams = append(flags.proto.OutParams, "lite")
+ case "":
+ // TODO(b/119714316): this should be equivalent to "lite" in
+ // order to match protoDeps, but some modules are depending on
+ // this behavior
+ flags.proto.OutTypeFlag = "--cpp_out"
+ default:
+ ctx.PropertyErrorf("proto.type", "unknown proto type %q",
+ String(p.Proto.Type))
+ }
- switch String(p.Proto.Type) {
- case "nanopb-c", "nanopb-c-enable_malloc", "nanopb-c-16bit", "nanopb-c-enable_malloc-16bit", "nanopb-c-32bit", "nanopb-c-enable_malloc-32bit":
- flags.protoC = true
- flags.protoOptionsFile = true
- flags.protoOutTypeFlag = "--nanopb_out"
- plugin = "protoc-gen-nanopb"
- case "full":
- flags.protoOutTypeFlag = "--cpp_out"
- case "lite":
- flags.protoOutTypeFlag = "--cpp_out"
- flags.protoOutParams = append(flags.protoOutParams, "lite")
- case "":
- // TODO(b/119714316): this should be equivalent to "lite" in
- // order to match protoDeps, but some modules are depending on
- // this behavior
- flags.protoOutTypeFlag = "--cpp_out"
- default:
- ctx.PropertyErrorf("proto.type", "unknown proto type %q",
- String(p.Proto.Type))
- }
-
- if plugin != "" {
- path := ctx.Config().HostToolPath(ctx, plugin)
- flags.protoDeps = append(flags.protoDeps, path)
- flags.protoFlags = append(flags.protoFlags, "--plugin="+path.String())
+ if plugin != "" {
+ path := ctx.Config().HostToolPath(ctx, plugin)
+ flags.proto.Deps = append(flags.proto.Deps, path)
+ flags.proto.Flags = append(flags.proto.Flags, "--plugin="+path.String())
+ }
}
return flags
diff --git a/cc/proto_test.go b/cc/proto_test.go
new file mode 100644
index 0000000..a7fcef9
--- /dev/null
+++ b/cc/proto_test.go
@@ -0,0 +1,75 @@
+// 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 (
+ "runtime"
+ "strings"
+ "testing"
+
+ "android/soong/android"
+)
+
+func TestProto(t *testing.T) {
+ t.Run("simple", func(t *testing.T) {
+ ctx := testCc(t, `
+ cc_library_shared {
+ name: "libfoo",
+ srcs: ["a.proto"],
+ }`)
+
+ proto := ctx.ModuleForTests("libfoo", "android_arm_armv7-a-neon_core_shared").Output("proto/a.pb.cc")
+
+ if cmd := proto.RuleParams.Command; !strings.Contains(cmd, "--cpp_out=") {
+ t.Errorf("expected '--cpp_out' in %q", cmd)
+ }
+ })
+
+ t.Run("plugin", func(t *testing.T) {
+ if runtime.GOOS != "linux" {
+ t.Skip("TODO(b/129763458): cc_binary_host tests fail on mac when trying to exec xcrun")
+ }
+ ctx := testCc(t, `
+ cc_binary_host {
+ name: "protoc-gen-foobar",
+ stl: "none",
+ }
+
+ cc_library_shared {
+ name: "libfoo",
+ srcs: ["a.proto"],
+ proto: {
+ plugin: "foobar",
+ },
+ }`)
+
+ buildOS := android.BuildOs.String()
+
+ proto := ctx.ModuleForTests("libfoo", "android_arm_armv7-a-neon_core_shared").Output("proto/a.pb.cc")
+ foobar := ctx.ModuleForTests("protoc-gen-foobar", buildOS+"_x86_64")
+
+ cmd := proto.RuleParams.Command
+ if w := "--foobar_out="; !strings.Contains(cmd, w) {
+ t.Errorf("expected %q in %q", w, cmd)
+ }
+
+ foobarPath := foobar.Module().(android.HostToolProvider).HostToolPath().String()
+
+ if w := "--plugin=protoc-gen-foobar=" + foobarPath; !strings.Contains(cmd, w) {
+ t.Errorf("expected %q in %q", w, cmd)
+ }
+ })
+
+}
diff --git a/cc/util.go b/cc/util.go
index 782bf61..5dcbaef 100644
--- a/cc/util.go
+++ b/cc/util.go
@@ -84,13 +84,9 @@
groupStaticLibs: in.GroupStaticLibs,
- protoDeps: in.protoDeps,
- protoFlags: strings.Join(in.protoFlags, " "),
- protoOutTypeFlag: in.protoOutTypeFlag,
- protoOutParams: strings.Join(in.protoOutParams, ","),
+ proto: in.proto,
protoC: in.protoC,
protoOptionsFile: in.protoOptionsFile,
- protoRoot: in.ProtoRoot,
}
}
diff --git a/cmd/dep_fixer/main.go b/cmd/dep_fixer/main.go
index 0647fb2..f94cf2f 100644
--- a/cmd/dep_fixer/main.go
+++ b/cmd/dep_fixer/main.go
@@ -29,30 +29,42 @@
func main() {
flag.Usage = func() {
- fmt.Fprintf(os.Stderr, "Usage: %s <depfile.d>", os.Args[0])
+ fmt.Fprintf(os.Stderr, "Usage: %s [-o <output>] <depfile.d> [<depfile.d>...]", os.Args[0])
flag.PrintDefaults()
}
output := flag.String("o", "", "Optional output file (defaults to rewriting source if necessary)")
flag.Parse()
- if flag.NArg() != 1 {
- log.Fatal("Expected a single file as an argument")
+ if flag.NArg() < 1 {
+ log.Fatal("Expected at least one input file as an argument")
}
- old, err := ioutil.ReadFile(flag.Arg(0))
- if err != nil {
- log.Fatalf("Error opening %q: %v", flag.Arg(0), err)
+ var mergedDeps *Deps
+ var firstInput []byte
+
+ for i, arg := range flag.Args() {
+ input, err := ioutil.ReadFile(arg)
+ if err != nil {
+ log.Fatalf("Error opening %q: %v", arg, err)
+ }
+
+ deps, err := Parse(arg, bytes.NewBuffer(append([]byte(nil), input...)))
+ if err != nil {
+ log.Fatalf("Failed to parse: %v", err)
+ }
+
+ if i == 0 {
+ mergedDeps = deps
+ firstInput = input
+ } else {
+ mergedDeps.Inputs = append(mergedDeps.Inputs, deps.Inputs...)
+ }
}
- deps, err := Parse(flag.Arg(0), bytes.NewBuffer(append([]byte(nil), old...)))
- if err != nil {
- log.Fatalf("Failed to parse: %v", err)
- }
-
- new := deps.Print()
+ new := mergedDeps.Print()
if *output == "" || *output == flag.Arg(0) {
- if !bytes.Equal(old, new) {
+ if !bytes.Equal(firstInput, new) {
err := ioutil.WriteFile(flag.Arg(0), new, 0666)
if err != nil {
log.Fatalf("Failed to write: %v", err)
diff --git a/cmd/diff_target_files/Android.bp b/cmd/diff_target_files/Android.bp
new file mode 100644
index 0000000..5397f4b
--- /dev/null
+++ b/cmd/diff_target_files/Android.bp
@@ -0,0 +1,16 @@
+blueprint_go_binary {
+ name: "diff_target_files",
+ srcs: [
+ "compare.go",
+ "diff_target_files.go",
+ "glob.go",
+ "target_files.go",
+ "whitelist.go",
+ "zip_artifact.go",
+ ],
+ testSrcs: [
+ "compare_test.go",
+ "glob_test.go",
+ "whitelist_test.go",
+ ],
+}
diff --git a/cmd/diff_target_files/compare.go b/cmd/diff_target_files/compare.go
new file mode 100644
index 0000000..00cd9ca
--- /dev/null
+++ b/cmd/diff_target_files/compare.go
@@ -0,0 +1,133 @@
+// Copyright 2019 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"
+ "fmt"
+)
+
+// compareTargetFiles takes two ZipArtifacts and compares the files they contain by examining
+// the path, size, and CRC of each file.
+func compareTargetFiles(priZip, refZip ZipArtifact, artifact string, whitelists []whitelist, filters []string) (zipDiff, error) {
+ priZipFiles, err := priZip.Files()
+ if err != nil {
+ return zipDiff{}, fmt.Errorf("error fetching target file lists from primary zip %v", err)
+ }
+
+ refZipFiles, err := refZip.Files()
+ if err != nil {
+ return zipDiff{}, fmt.Errorf("error fetching target file lists from reference zip %v", err)
+ }
+
+ priZipFiles, err = filterTargetZipFiles(priZipFiles, artifact, filters)
+ if err != nil {
+ return zipDiff{}, err
+ }
+
+ refZipFiles, err = filterTargetZipFiles(refZipFiles, artifact, filters)
+ if err != nil {
+ return zipDiff{}, err
+ }
+
+ // Compare the file lists from both builds
+ diff := diffTargetFilesLists(refZipFiles, priZipFiles)
+
+ return applyWhitelists(diff, whitelists)
+}
+
+// zipDiff contains the list of files that differ between two zip files.
+type zipDiff struct {
+ modified [][2]*ZipArtifactFile
+ onlyInA, onlyInB []*ZipArtifactFile
+}
+
+// String pretty-prints the list of files that differ between two zip files.
+func (d *zipDiff) String() string {
+ buf := &bytes.Buffer{}
+
+ must := func(n int, err error) {
+ if err != nil {
+ panic(err)
+ }
+ }
+
+ var sizeChange int64
+
+ if len(d.modified) > 0 {
+ must(fmt.Fprintln(buf, "files modified:"))
+ for _, f := range d.modified {
+ must(fmt.Fprintf(buf, " %v (%v bytes -> %v bytes)\n", f[0].Name, f[0].UncompressedSize64, f[1].UncompressedSize64))
+ sizeChange += int64(f[1].UncompressedSize64) - int64(f[0].UncompressedSize64)
+ }
+ }
+
+ if len(d.onlyInA) > 0 {
+ must(fmt.Fprintln(buf, "files removed:"))
+ for _, f := range d.onlyInA {
+ must(fmt.Fprintf(buf, " - %v (%v bytes)\n", f.Name, f.UncompressedSize64))
+ sizeChange -= int64(f.UncompressedSize64)
+ }
+ }
+
+ if len(d.onlyInB) > 0 {
+ must(fmt.Fprintln(buf, "files added:"))
+ for _, f := range d.onlyInB {
+ must(fmt.Fprintf(buf, " + %v (%v bytes)\n", f.Name, f.UncompressedSize64))
+ sizeChange += int64(f.UncompressedSize64)
+ }
+ }
+
+ if len(d.modified) > 0 || len(d.onlyInA) > 0 || len(d.onlyInB) > 0 {
+ must(fmt.Fprintf(buf, "total size change: %v bytes\n", sizeChange))
+ }
+
+ return buf.String()
+}
+
+func diffTargetFilesLists(a, b []*ZipArtifactFile) zipDiff {
+ i := 0
+ j := 0
+
+ diff := zipDiff{}
+
+ for i < len(a) && j < len(b) {
+ if a[i].Name == b[j].Name {
+ if a[i].UncompressedSize64 != b[j].UncompressedSize64 || a[i].CRC32 != b[j].CRC32 {
+ diff.modified = append(diff.modified, [2]*ZipArtifactFile{a[i], b[j]})
+ }
+ i++
+ j++
+ } else if a[i].Name < b[j].Name {
+ // a[i] is not present in b
+ diff.onlyInA = append(diff.onlyInA, a[i])
+ i++
+ } else {
+ // b[j] is not present in a
+ diff.onlyInB = append(diff.onlyInB, b[j])
+ j++
+ }
+ }
+ for i < len(a) {
+ diff.onlyInA = append(diff.onlyInA, a[i])
+ i++
+ }
+ for j < len(b) {
+ diff.onlyInB = append(diff.onlyInB, b[j])
+ j++
+ }
+
+ return diff
+}
diff --git a/cmd/diff_target_files/compare_test.go b/cmd/diff_target_files/compare_test.go
new file mode 100644
index 0000000..9d3f8a5
--- /dev/null
+++ b/cmd/diff_target_files/compare_test.go
@@ -0,0 +1,131 @@
+// Copyright 2019 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 (
+ "archive/zip"
+ "reflect"
+ "testing"
+)
+
+func TestDiffTargetFilesLists(t *testing.T) {
+ zipArtifactFile := func(name string, crc32 uint32, size uint64) *ZipArtifactFile {
+ return &ZipArtifactFile{
+ File: &zip.File{
+ FileHeader: zip.FileHeader{
+ Name: name,
+ CRC32: crc32,
+ UncompressedSize64: size,
+ },
+ },
+ }
+ }
+ x0 := zipArtifactFile("x", 0, 0)
+ x1 := zipArtifactFile("x", 1, 0)
+ x2 := zipArtifactFile("x", 0, 2)
+ y0 := zipArtifactFile("y", 0, 0)
+ //y1 := zipArtifactFile("y", 1, 0)
+ //y2 := zipArtifactFile("y", 1, 2)
+ z0 := zipArtifactFile("z", 0, 0)
+ z1 := zipArtifactFile("z", 1, 0)
+ //z2 := zipArtifactFile("z", 1, 2)
+
+ testCases := []struct {
+ name string
+ a, b []*ZipArtifactFile
+ diff zipDiff
+ }{
+ {
+ name: "same",
+ a: []*ZipArtifactFile{x0, y0, z0},
+ b: []*ZipArtifactFile{x0, y0, z0},
+ diff: zipDiff{nil, nil, nil},
+ },
+ {
+ name: "first only in a",
+ a: []*ZipArtifactFile{x0, y0, z0},
+ b: []*ZipArtifactFile{y0, z0},
+ diff: zipDiff{nil, []*ZipArtifactFile{x0}, nil},
+ },
+ {
+ name: "middle only in a",
+ a: []*ZipArtifactFile{x0, y0, z0},
+ b: []*ZipArtifactFile{x0, z0},
+ diff: zipDiff{nil, []*ZipArtifactFile{y0}, nil},
+ },
+ {
+ name: "last only in a",
+ a: []*ZipArtifactFile{x0, y0, z0},
+ b: []*ZipArtifactFile{x0, y0},
+ diff: zipDiff{nil, []*ZipArtifactFile{z0}, nil},
+ },
+
+ {
+ name: "first only in b",
+ a: []*ZipArtifactFile{y0, z0},
+ b: []*ZipArtifactFile{x0, y0, z0},
+ diff: zipDiff{nil, nil, []*ZipArtifactFile{x0}},
+ },
+ {
+ name: "middle only in b",
+ a: []*ZipArtifactFile{x0, z0},
+ b: []*ZipArtifactFile{x0, y0, z0},
+ diff: zipDiff{nil, nil, []*ZipArtifactFile{y0}},
+ },
+ {
+ name: "last only in b",
+ a: []*ZipArtifactFile{x0, y0},
+ b: []*ZipArtifactFile{x0, y0, z0},
+ diff: zipDiff{nil, nil, []*ZipArtifactFile{z0}},
+ },
+
+ {
+ name: "diff",
+ a: []*ZipArtifactFile{x0},
+ b: []*ZipArtifactFile{x1},
+ diff: zipDiff{[][2]*ZipArtifactFile{{x0, x1}}, nil, nil},
+ },
+ {
+ name: "diff plus unique last",
+ a: []*ZipArtifactFile{x0, y0},
+ b: []*ZipArtifactFile{x1, z0},
+ diff: zipDiff{[][2]*ZipArtifactFile{{x0, x1}}, []*ZipArtifactFile{y0}, []*ZipArtifactFile{z0}},
+ },
+ {
+ name: "diff plus unique first",
+ a: []*ZipArtifactFile{x0, z0},
+ b: []*ZipArtifactFile{y0, z1},
+ diff: zipDiff{[][2]*ZipArtifactFile{{z0, z1}}, []*ZipArtifactFile{x0}, []*ZipArtifactFile{y0}},
+ },
+ {
+ name: "diff size",
+ a: []*ZipArtifactFile{x0},
+ b: []*ZipArtifactFile{x2},
+ diff: zipDiff{[][2]*ZipArtifactFile{{x0, x2}}, nil, nil},
+ },
+ }
+
+ for _, test := range testCases {
+ t.Run(test.name, func(t *testing.T) {
+ diff := diffTargetFilesLists(test.a, test.b)
+
+ if !reflect.DeepEqual(diff, test.diff) {
+
+ t.Errorf("diffTargetFilesLists = %v, %v, %v", diff.modified, diff.onlyInA, diff.onlyInB)
+ t.Errorf(" want %v, %v, %v", test.diff.modified, test.diff.onlyInA, test.diff.onlyInB)
+ }
+ })
+ }
+}
diff --git a/cmd/diff_target_files/diff_target_files.go b/cmd/diff_target_files/diff_target_files.go
new file mode 100644
index 0000000..75bc8ee
--- /dev/null
+++ b/cmd/diff_target_files/diff_target_files.go
@@ -0,0 +1,82 @@
+// Copyright 2019 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 (
+ "flag"
+ "fmt"
+ "os"
+ "strings"
+)
+
+var (
+ whitelists = newMultiString("whitelist", "whitelist patterns in the form <pattern>[:<regex of line to ignore>]")
+ whitelistFiles = newMultiString("whitelist_file", "files containing whitelist definitions")
+
+ filters = newMultiString("filter", "filter patterns to apply to files in target-files.zip before comparing")
+)
+
+func newMultiString(name, usage string) *multiString {
+ var f multiString
+ flag.Var(&f, name, usage)
+ return &f
+}
+
+type multiString []string
+
+func (ms *multiString) String() string { return strings.Join(*ms, ", ") }
+func (ms *multiString) Set(s string) error { *ms = append(*ms, s); return nil }
+
+func main() {
+ flag.Parse()
+
+ if flag.NArg() != 2 {
+ fmt.Fprintf(os.Stderr, "Error, exactly two arguments are required\n")
+ os.Exit(1)
+ }
+
+ whitelists, err := parseWhitelists(*whitelists, *whitelistFiles)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "Error parsing whitelists: %v\n", err)
+ os.Exit(1)
+ }
+
+ priZip, err := NewLocalZipArtifact(flag.Arg(0))
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "Error opening zip file %v: %v\n", flag.Arg(0), err)
+ os.Exit(1)
+ }
+ defer priZip.Close()
+
+ refZip, err := NewLocalZipArtifact(flag.Arg(1))
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "Error opening zip file %v: %v\n", flag.Arg(1), err)
+ os.Exit(1)
+ }
+ defer refZip.Close()
+
+ diff, err := compareTargetFiles(priZip, refZip, targetFilesPattern, whitelists, *filters)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "Error comparing zip files: %v\n", err)
+ os.Exit(1)
+ }
+
+ fmt.Print(diff.String())
+
+ if len(diff.modified) > 0 || len(diff.onlyInA) > 0 || len(diff.onlyInB) > 0 {
+ fmt.Fprintln(os.Stderr, "differences found")
+ os.Exit(1)
+ }
+}
diff --git a/cmd/diff_target_files/glob.go b/cmd/diff_target_files/glob.go
new file mode 100644
index 0000000..ed91af7
--- /dev/null
+++ b/cmd/diff_target_files/glob.go
@@ -0,0 +1,81 @@
+// Copyright 2019 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 (
+ "errors"
+ "path/filepath"
+ "strings"
+)
+
+// Match returns true if name matches pattern using the same rules as filepath.Match, but supporting
+// recursive globs (**).
+func Match(pattern, name string) (bool, error) {
+ if filepath.Base(pattern) == "**" {
+ return false, errors.New("pattern has '**' as last path element")
+ }
+
+ patternDir := pattern[len(pattern)-1] == '/'
+ nameDir := name[len(name)-1] == '/'
+
+ if patternDir != nameDir {
+ return false, nil
+ }
+
+ if nameDir {
+ name = name[:len(name)-1]
+ pattern = pattern[:len(pattern)-1]
+ }
+
+ for {
+ var patternFile, nameFile string
+ pattern, patternFile = filepath.Dir(pattern), filepath.Base(pattern)
+
+ if patternFile == "**" {
+ if strings.Contains(pattern, "**") {
+ return false, errors.New("pattern contains multiple '**'")
+ }
+ // Test if the any prefix of name matches the part of the pattern before **
+ for {
+ if name == "." || name == "/" {
+ return name == pattern, nil
+ }
+ if match, err := filepath.Match(pattern, name); err != nil {
+ return false, err
+ } else if match {
+ return true, nil
+ }
+ name = filepath.Dir(name)
+ }
+ } else if strings.Contains(patternFile, "**") {
+ return false, errors.New("pattern contains other characters between '**' and path separator")
+ }
+
+ name, nameFile = filepath.Dir(name), filepath.Base(name)
+
+ if nameFile == "." && patternFile == "." {
+ return true, nil
+ } else if nameFile == "/" && patternFile == "/" {
+ return true, nil
+ } else if nameFile == "." || patternFile == "." || nameFile == "/" || patternFile == "/" {
+ return false, nil
+ }
+
+ match, err := filepath.Match(patternFile, nameFile)
+ if err != nil || !match {
+ return match, err
+ }
+ }
+}
diff --git a/cmd/diff_target_files/glob_test.go b/cmd/diff_target_files/glob_test.go
new file mode 100644
index 0000000..63df68d
--- /dev/null
+++ b/cmd/diff_target_files/glob_test.go
@@ -0,0 +1,158 @@
+// Copyright 2019 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 (
+ "testing"
+)
+
+func TestMatch(t *testing.T) {
+ testCases := []struct {
+ pattern, name string
+ match bool
+ }{
+ {"a/*", "b/", false},
+ {"a/*", "b/a", false},
+ {"a/*", "b/b/", false},
+ {"a/*", "b/b/c", false},
+ {"a/**/*", "b/", false},
+ {"a/**/*", "b/a", false},
+ {"a/**/*", "b/b/", false},
+ {"a/**/*", "b/b/c", false},
+
+ {"a/*", "a/", false},
+ {"a/*", "a/a", true},
+ {"a/*", "a/b/", false},
+ {"a/*", "a/b/c", false},
+
+ {"a/*/", "a/", false},
+ {"a/*/", "a/a", false},
+ {"a/*/", "a/b/", true},
+ {"a/*/", "a/b/c", false},
+
+ {"a/**/*", "a/", false},
+ {"a/**/*", "a/a", true},
+ {"a/**/*", "a/b/", false},
+ {"a/**/*", "a/b/c", true},
+
+ {"a/**/*/", "a/", false},
+ {"a/**/*/", "a/a", false},
+ {"a/**/*/", "a/b/", true},
+ {"a/**/*/", "a/b/c", false},
+
+ {"**/*", "a/", false},
+ {"**/*", "a/a", true},
+ {"**/*", "a/b/", false},
+ {"**/*", "a/b/c", true},
+
+ {"**/*/", "a/", true},
+ {"**/*/", "a/a", false},
+ {"**/*/", "a/b/", true},
+ {"**/*/", "a/b/c", false},
+
+ {`a/\*\*/\*`, `a/**/*`, true},
+ {`a/\*\*/\*`, `a/a/*`, false},
+ {`a/\*\*/\*`, `a/**/a`, false},
+ {`a/\*\*/\*`, `a/a/a`, false},
+
+ {`a/**/\*`, `a/**/*`, true},
+ {`a/**/\*`, `a/a/*`, true},
+ {`a/**/\*`, `a/**/a`, false},
+ {`a/**/\*`, `a/a/a`, false},
+
+ {`a/\*\*/*`, `a/**/*`, true},
+ {`a/\*\*/*`, `a/a/*`, false},
+ {`a/\*\*/*`, `a/**/a`, true},
+ {`a/\*\*/*`, `a/a/a`, false},
+
+ {`*/**/a`, `a/a/a`, true},
+ {`*/**/a`, `*/a/a`, true},
+ {`*/**/a`, `a/**/a`, true},
+ {`*/**/a`, `*/**/a`, true},
+
+ {`\*/\*\*/a`, `a/a/a`, false},
+ {`\*/\*\*/a`, `*/a/a`, false},
+ {`\*/\*\*/a`, `a/**/a`, false},
+ {`\*/\*\*/a`, `*/**/a`, true},
+
+ {`a/?`, `a/?`, true},
+ {`a/?`, `a/a`, true},
+ {`a/\?`, `a/?`, true},
+ {`a/\?`, `a/a`, false},
+
+ {`a/?`, `a/?`, true},
+ {`a/?`, `a/a`, true},
+ {`a/\?`, `a/?`, true},
+ {`a/\?`, `a/a`, false},
+
+ {`a/[a-c]`, `a/b`, true},
+ {`a/[abc]`, `a/b`, true},
+
+ {`a/\[abc]`, `a/b`, false},
+ {`a/\[abc]`, `a/[abc]`, true},
+
+ {`a/\[abc\]`, `a/b`, false},
+ {`a/\[abc\]`, `a/[abc]`, true},
+
+ {`a/?`, `a/?`, true},
+ {`a/?`, `a/a`, true},
+ {`a/\?`, `a/?`, true},
+ {`a/\?`, `a/a`, false},
+
+ {"/a/*", "/a/", false},
+ {"/a/*", "/a/a", true},
+ {"/a/*", "/a/b/", false},
+ {"/a/*", "/a/b/c", false},
+
+ {"/a/*/", "/a/", false},
+ {"/a/*/", "/a/a", false},
+ {"/a/*/", "/a/b/", true},
+ {"/a/*/", "/a/b/c", false},
+
+ {"/a/**/*", "/a/", false},
+ {"/a/**/*", "/a/a", true},
+ {"/a/**/*", "/a/b/", false},
+ {"/a/**/*", "/a/b/c", true},
+
+ {"/**/*", "/a/", false},
+ {"/**/*", "/a/a", true},
+ {"/**/*", "/a/b/", false},
+ {"/**/*", "/a/b/c", true},
+
+ {"/**/*/", "/a/", true},
+ {"/**/*/", "/a/a", false},
+ {"/**/*/", "/a/b/", true},
+ {"/**/*/", "/a/b/c", false},
+
+ {`a`, `/a`, false},
+ {`/a`, `a`, false},
+ {`*`, `/a`, false},
+ {`/*`, `a`, false},
+ {`**/*`, `/a`, false},
+ {`/**/*`, `a`, false},
+ }
+
+ for _, test := range testCases {
+ t.Run(test.pattern+","+test.name, func(t *testing.T) {
+ match, err := Match(test.pattern, test.name)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if match != test.match {
+ t.Errorf("want: %v, got %v", test.match, match)
+ }
+ })
+ }
+}
diff --git a/cmd/diff_target_files/known_nondeterminism.whitelist b/cmd/diff_target_files/known_nondeterminism.whitelist
new file mode 100644
index 0000000..6d71403
--- /dev/null
+++ b/cmd/diff_target_files/known_nondeterminism.whitelist
@@ -0,0 +1,10 @@
+// List of files that are known to be non-deterministic, along with the
+// bug number to tracking fixing the non-determinism.
+[
+ {
+ "Paths": [
+ // b/120039850
+ "system/framework/oat/*/services.art"
+ ]
+ }
+]
diff --git a/cmd/diff_target_files/props.whitelist b/cmd/diff_target_files/props.whitelist
new file mode 100644
index 0000000..9245b8b
--- /dev/null
+++ b/cmd/diff_target_files/props.whitelist
@@ -0,0 +1,18 @@
+[
+ // Ignore date, version and hostname properties in build.prop and prop.default files.
+ {
+ "Paths": [
+ "**/build.prop",
+ "**/prop.default"
+ ],
+ "IgnoreMatchingLines": [
+ "ro\\..*build\\.date=.*",
+ "ro\\..*build\\.date\\.utc=.*",
+ "ro\\..*build\\.version\\.incremental=.*",
+ "ro\\..*build\\.fingerprint=.*",
+ "ro\\.build\\.display\\.id=.*",
+ "ro\\.build\\.description=.*",
+ "ro\\.build\\.host=.*"
+ ]
+ }
+]
\ No newline at end of file
diff --git a/cmd/diff_target_files/target_files.go b/cmd/diff_target_files/target_files.go
new file mode 100644
index 0000000..8705ca7
--- /dev/null
+++ b/cmd/diff_target_files/target_files.go
@@ -0,0 +1,86 @@
+// Copyright 2019 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 (
+ "fmt"
+ "strings"
+)
+
+const targetFilesPattern = "*-target_files-*.zip"
+
+var targetZipPartitions = []string{
+ "BOOT/RAMDISK/",
+ "BOOT/",
+ "DATA/",
+ "ODM/",
+ "OEM/",
+ "PRODUCT/",
+ "PRODUCT_SERVICES/",
+ "ROOT/",
+ "SYSTEM/",
+ "SYSTEM_OTHER/",
+ "VENDOR/",
+}
+
+var targetZipFilter = []string{
+ "IMAGES/",
+ "OTA/",
+ "META/",
+ "PREBUILT_IMAGES/",
+ "RADIO/",
+}
+
+func filterTargetZipFiles(files []*ZipArtifactFile, artifact string, patterns []string) ([]*ZipArtifactFile, error) {
+ var ret []*ZipArtifactFile
+outer:
+ for _, f := range files {
+ if f.FileInfo().IsDir() {
+ continue
+ }
+
+ if artifact == targetFilesPattern {
+ found := false
+ for _, p := range targetZipPartitions {
+ if strings.HasPrefix(f.Name, p) {
+ f.Name = strings.ToLower(p) + strings.TrimPrefix(f.Name, p)
+ found = true
+ }
+ }
+ for _, filter := range targetZipFilter {
+ if strings.HasPrefix(f.Name, filter) {
+ continue outer
+ }
+ }
+
+ if !found {
+ return nil, fmt.Errorf("unmatched prefix for %s", f.Name)
+ }
+ }
+
+ if patterns != nil {
+ for _, pattern := range patterns {
+ match, _ := Match(pattern, f.Name)
+ if match {
+ ret = append(ret, f)
+ }
+ }
+ } else {
+ ret = append(ret, f)
+ }
+ }
+
+ return ret, nil
+}
diff --git a/cmd/diff_target_files/whitelist.go b/cmd/diff_target_files/whitelist.go
new file mode 100644
index 0000000..f00fc1e
--- /dev/null
+++ b/cmd/diff_target_files/whitelist.go
@@ -0,0 +1,251 @@
+// Copyright 2019 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 (
+ "bufio"
+ "bytes"
+ "encoding/json"
+ "io"
+ "os"
+ "regexp"
+ "strings"
+ "unicode"
+)
+
+type jsonWhitelist struct {
+ Paths []string
+ IgnoreMatchingLines []string
+}
+
+type whitelist struct {
+ path string
+ ignoreMatchingLines []string
+}
+
+func parseWhitelists(whitelists []string, whitelistFiles []string) ([]whitelist, error) {
+ var ret []whitelist
+
+ add := func(path string, ignoreMatchingLines []string) {
+ for _, x := range ret {
+ if x.path == path {
+ x.ignoreMatchingLines = append(x.ignoreMatchingLines, ignoreMatchingLines...)
+ return
+ }
+ }
+
+ ret = append(ret, whitelist{
+ path: path,
+ ignoreMatchingLines: ignoreMatchingLines,
+ })
+ }
+
+ for _, file := range whitelistFiles {
+ newWhitelists, err := parseWhitelistFile(file)
+ if err != nil {
+ return nil, err
+ }
+
+ for _, w := range newWhitelists {
+ add(w.path, w.ignoreMatchingLines)
+ }
+ }
+
+ for _, s := range whitelists {
+ colon := strings.IndexRune(s, ':')
+ var ignoreMatchingLines []string
+ if colon >= 0 {
+ ignoreMatchingLines = []string{s[colon+1:]}
+ }
+ add(s, ignoreMatchingLines)
+ }
+
+ return ret, nil
+}
+
+func parseWhitelistFile(file string) ([]whitelist, error) {
+ r, err := os.Open(file)
+ if err != nil {
+ return nil, err
+ }
+ defer r.Close()
+
+ d := json.NewDecoder(newJSONCommentStripper(r))
+
+ var jsonWhitelists []jsonWhitelist
+
+ err = d.Decode(&jsonWhitelists)
+
+ var whitelists []whitelist
+ for _, w := range jsonWhitelists {
+ for _, p := range w.Paths {
+ whitelists = append(whitelists, whitelist{
+ path: p,
+ ignoreMatchingLines: w.IgnoreMatchingLines,
+ })
+ }
+ }
+
+ return whitelists, err
+}
+
+func filterModifiedPaths(l [][2]*ZipArtifactFile, whitelists []whitelist) ([][2]*ZipArtifactFile, error) {
+outer:
+ for i := 0; i < len(l); i++ {
+ for _, w := range whitelists {
+ if match, err := Match(w.path, l[i][0].Name); err != nil {
+ return l, err
+ } else if match {
+ if match, err := diffIgnoringMatchingLines(l[i][0], l[i][1], w.ignoreMatchingLines); err != nil {
+ return l, err
+ } else if match || len(w.ignoreMatchingLines) == 0 {
+ l = append(l[:i], l[i+1:]...)
+ i--
+ }
+ continue outer
+ }
+ }
+ }
+
+ if len(l) == 0 {
+ l = nil
+ }
+
+ return l, nil
+}
+
+func filterNewPaths(l []*ZipArtifactFile, whitelists []whitelist) ([]*ZipArtifactFile, error) {
+outer:
+ for i := 0; i < len(l); i++ {
+ for _, w := range whitelists {
+ if match, err := Match(w.path, l[i].Name); err != nil {
+ return l, err
+ } else if match && len(w.ignoreMatchingLines) == 0 {
+ l = append(l[:i], l[i+1:]...)
+ i--
+ }
+ continue outer
+ }
+ }
+
+ if len(l) == 0 {
+ l = nil
+ }
+
+ return l, nil
+}
+
+func diffIgnoringMatchingLines(a *ZipArtifactFile, b *ZipArtifactFile, ignoreMatchingLines []string) (match bool, err error) {
+ lineMatchesIgnores := func(b []byte) (bool, error) {
+ for _, m := range ignoreMatchingLines {
+ if match, err := regexp.Match(m, b); err != nil {
+ return false, err
+ } else if match {
+ return match, nil
+ }
+ }
+ return false, nil
+ }
+
+ filter := func(z *ZipArtifactFile) ([]byte, error) {
+ var ret []byte
+
+ r, err := z.Open()
+ if err != nil {
+ return nil, err
+ }
+ s := bufio.NewScanner(r)
+
+ for s.Scan() {
+ if match, err := lineMatchesIgnores(s.Bytes()); err != nil {
+ return nil, err
+ } else if !match {
+ ret = append(ret, "\n"...)
+ ret = append(ret, s.Bytes()...)
+ }
+ }
+
+ return ret, nil
+ }
+
+ bufA, err := filter(a)
+ if err != nil {
+ return false, err
+ }
+ bufB, err := filter(b)
+ if err != nil {
+ return false, err
+ }
+
+ return bytes.Compare(bufA, bufB) == 0, nil
+}
+
+func applyWhitelists(diff zipDiff, whitelists []whitelist) (zipDiff, error) {
+ var err error
+
+ diff.modified, err = filterModifiedPaths(diff.modified, whitelists)
+ if err != nil {
+ return diff, err
+ }
+ diff.onlyInA, err = filterNewPaths(diff.onlyInA, whitelists)
+ if err != nil {
+ return diff, err
+ }
+ diff.onlyInB, err = filterNewPaths(diff.onlyInB, whitelists)
+ if err != nil {
+ return diff, err
+ }
+
+ return diff, nil
+}
+
+func newJSONCommentStripper(r io.Reader) *jsonCommentStripper {
+ return &jsonCommentStripper{
+ r: bufio.NewReader(r),
+ }
+}
+
+type jsonCommentStripper struct {
+ r *bufio.Reader
+ b []byte
+ err error
+}
+
+func (j *jsonCommentStripper) Read(buf []byte) (int, error) {
+ for len(j.b) == 0 {
+ if j.err != nil {
+ return 0, j.err
+ }
+
+ j.b, j.err = j.r.ReadBytes('\n')
+
+ if isComment(j.b) {
+ j.b = nil
+ }
+ }
+
+ n := copy(buf, j.b)
+ j.b = j.b[n:]
+ return n, nil
+}
+
+var commentPrefix = []byte("//")
+
+func isComment(b []byte) bool {
+ for len(b) > 0 && unicode.IsSpace(rune(b[0])) {
+ b = b[1:]
+ }
+ return bytes.HasPrefix(b, commentPrefix)
+}
diff --git a/cmd/diff_target_files/whitelist_test.go b/cmd/diff_target_files/whitelist_test.go
new file mode 100644
index 0000000..4b19fdd
--- /dev/null
+++ b/cmd/diff_target_files/whitelist_test.go
@@ -0,0 +1,126 @@
+// Copyright 2019 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 (
+ "archive/zip"
+ "bytes"
+ "reflect"
+ "testing"
+)
+
+func bytesToZipArtifactFile(name string, data []byte) *ZipArtifactFile {
+ buf := &bytes.Buffer{}
+ w := zip.NewWriter(buf)
+ f, err := w.Create(name)
+ if err != nil {
+ panic(err)
+ }
+ _, err = f.Write(data)
+ if err != nil {
+ panic(err)
+ }
+
+ w.Close()
+
+ r, err := zip.NewReader(bytes.NewReader(buf.Bytes()), int64(buf.Len()))
+ if err != nil {
+ panic(err)
+ }
+
+ return &ZipArtifactFile{r.File[0]}
+}
+
+var f1a = bytesToZipArtifactFile("dir/f1", []byte(`
+a
+foo: bar
+c
+`))
+
+var f1b = bytesToZipArtifactFile("dir/f1", []byte(`
+a
+foo: baz
+c
+`))
+
+var f2 = bytesToZipArtifactFile("dir/f2", nil)
+
+func Test_applyWhitelists(t *testing.T) {
+ type args struct {
+ diff zipDiff
+ whitelists []whitelist
+ }
+ tests := []struct {
+ name string
+ args args
+ want zipDiff
+ wantErr bool
+ }{
+ {
+ name: "simple",
+ args: args{
+ diff: zipDiff{
+ onlyInA: []*ZipArtifactFile{f1a, f2},
+ },
+ whitelists: []whitelist{{path: "dir/f1"}},
+ },
+ want: zipDiff{
+ onlyInA: []*ZipArtifactFile{f2},
+ },
+ },
+ {
+ name: "glob",
+ args: args{
+ diff: zipDiff{
+ onlyInA: []*ZipArtifactFile{f1a, f2},
+ },
+ whitelists: []whitelist{{path: "dir/*"}},
+ },
+ want: zipDiff{},
+ },
+ {
+ name: "modified",
+ args: args{
+ diff: zipDiff{
+ modified: [][2]*ZipArtifactFile{{f1a, f1b}},
+ },
+ whitelists: []whitelist{{path: "dir/*"}},
+ },
+ want: zipDiff{},
+ },
+ {
+ name: "matching lines",
+ args: args{
+ diff: zipDiff{
+ modified: [][2]*ZipArtifactFile{{f1a, f1b}},
+ },
+ whitelists: []whitelist{{path: "dir/*", ignoreMatchingLines: []string{"foo: .*"}}},
+ },
+ want: zipDiff{},
+ },
+ }
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ got, err := applyWhitelists(tt.args.diff, tt.args.whitelists)
+ if (err != nil) != tt.wantErr {
+ t.Errorf("applyWhitelists() error = %v, wantErr %v", err, tt.wantErr)
+ return
+ }
+ if !reflect.DeepEqual(got, tt.want) {
+ t.Errorf("applyWhitelists() = %v, want %v", got, tt.want)
+ }
+ })
+ }
+}
diff --git a/cmd/diff_target_files/zip_artifact.go b/cmd/diff_target_files/zip_artifact.go
new file mode 100644
index 0000000..08ce889
--- /dev/null
+++ b/cmd/diff_target_files/zip_artifact.go
@@ -0,0 +1,174 @@
+// Copyright 2019 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 (
+ "archive/zip"
+ "context"
+ "fmt"
+ "hash/crc32"
+ "io"
+ "io/ioutil"
+ "os"
+ "path/filepath"
+)
+
+// ZipArtifact represents a zip file that may be local or remote.
+type ZipArtifact interface {
+ // Files returns the list of files contained in the zip file.
+ Files() ([]*ZipArtifactFile, error)
+
+ // Close closes the zip file artifact.
+ Close()
+}
+
+// localZipArtifact is a handle to a local zip file artifact.
+type localZipArtifact struct {
+ zr *zip.ReadCloser
+ files []*ZipArtifactFile
+}
+
+// NewLocalZipArtifact returns a ZipArtifact for a local zip file..
+func NewLocalZipArtifact(name string) (ZipArtifact, error) {
+ zr, err := zip.OpenReader(name)
+ if err != nil {
+ return nil, err
+ }
+
+ var files []*ZipArtifactFile
+ for _, zf := range zr.File {
+ files = append(files, &ZipArtifactFile{zf})
+ }
+
+ return &localZipArtifact{
+ zr: zr,
+ files: files,
+ }, nil
+}
+
+// Files returns the list of files contained in the local zip file artifact.
+func (z *localZipArtifact) Files() ([]*ZipArtifactFile, error) {
+ return z.files, nil
+}
+
+// Close closes the buffered reader of the local zip file artifact.
+func (z *localZipArtifact) Close() {
+ z.zr.Close()
+}
+
+// ZipArtifactFile contains a zip.File handle to the data inside the remote *-target_files-*.zip
+// build artifact.
+type ZipArtifactFile struct {
+ *zip.File
+}
+
+// Extract begins extract a file from inside a ZipArtifact. It returns an
+// ExtractedZipArtifactFile handle.
+func (zf *ZipArtifactFile) Extract(ctx context.Context, dir string,
+ limiter chan bool) *ExtractedZipArtifactFile {
+
+ d := &ExtractedZipArtifactFile{
+ initCh: make(chan struct{}),
+ }
+
+ go func() {
+ defer close(d.initCh)
+ limiter <- true
+ defer func() { <-limiter }()
+
+ zr, err := zf.Open()
+ if err != nil {
+ d.err = err
+ return
+ }
+ defer zr.Close()
+
+ crc := crc32.NewIEEE()
+ r := io.TeeReader(zr, crc)
+
+ if filepath.Clean(zf.Name) != zf.Name {
+ d.err = fmt.Errorf("invalid filename %q", zf.Name)
+ return
+ }
+ path := filepath.Join(dir, zf.Name)
+
+ err = os.MkdirAll(filepath.Dir(path), 0777)
+ if err != nil {
+ d.err = err
+ return
+ }
+
+ err = os.Remove(path)
+ if err != nil && !os.IsNotExist(err) {
+ d.err = err
+ return
+ }
+
+ if zf.Mode().IsRegular() {
+ w, err := os.OpenFile(path, os.O_CREATE|os.O_WRONLY, zf.Mode())
+ if err != nil {
+ d.err = err
+ return
+ }
+ defer w.Close()
+
+ _, err = io.Copy(w, r)
+ if err != nil {
+ d.err = err
+ return
+ }
+ } else if zf.Mode()&os.ModeSymlink != 0 {
+ target, err := ioutil.ReadAll(r)
+ if err != nil {
+ d.err = err
+ return
+ }
+
+ err = os.Symlink(string(target), path)
+ if err != nil {
+ d.err = err
+ return
+ }
+ } else {
+ d.err = fmt.Errorf("unknown mode %q", zf.Mode())
+ return
+ }
+
+ if crc.Sum32() != zf.CRC32 {
+ d.err = fmt.Errorf("crc mismatch for %v", zf.Name)
+ return
+ }
+
+ d.path = path
+ }()
+
+ return d
+}
+
+// ExtractedZipArtifactFile is a handle to a downloaded file from a remoteZipArtifact. The download
+// may still be in progress, and will be complete with Path() returns.
+type ExtractedZipArtifactFile struct {
+ initCh chan struct{}
+ err error
+
+ path string
+}
+
+// Path returns the path to the downloaded file and any errors that occurred during the download.
+// It will block until the download is complete.
+func (d *ExtractedZipArtifactFile) Path() (string, error) {
+ <-d.initCh
+ return d.path, d.err
+}
diff --git a/cmd/soong_env/soong_env.go b/cmd/soong_env/soong_env.go
index 933e525..d305d83 100644
--- a/cmd/soong_env/soong_env.go
+++ b/cmd/soong_env/soong_env.go
@@ -15,7 +15,7 @@
// soong_glob is the command line tool that checks if the list of files matching a glob has
// changed, and only updates the output file list if it has changed. It is used to optimize
// out build.ninja regenerations when non-matching files are added. See
-// android/soong/common/glob.go for a longer description.
+// android/soong/android/glob.go for a longer description.
package main
import (
diff --git a/genrule/genrule.go b/genrule/genrule.go
index 32acd8c..e259b1d 100644
--- a/genrule/genrule.go
+++ b/genrule/genrule.go
@@ -49,8 +49,10 @@
GeneratedDeps() android.Paths
}
+// Alias for android.HostToolProvider
+// Deprecated: use android.HostToolProvider instead.
type HostToolProvider interface {
- HostToolPath() android.OptionalPath
+ android.HostToolProvider
}
type hostToolDependencyTag struct {
@@ -193,7 +195,7 @@
tool := ctx.OtherModuleName(module)
var path android.OptionalPath
- if t, ok := module.(HostToolProvider); ok {
+ if t, ok := module.(android.HostToolProvider); ok {
if !t.(android.Module).Enabled() {
if ctx.Config().AllowMissingDependencies() {
ctx.AddMissingDependencies([]string{tool})
diff --git a/genrule/genrule_test.go b/genrule/genrule_test.go
index 19b22f7..5cb51b8 100644
--- a/genrule/genrule_test.go
+++ b/genrule/genrule_test.go
@@ -527,4 +527,4 @@
return android.OptionalPathForPath(t.outputFile)
}
-var _ HostToolProvider = (*testTool)(nil)
+var _ android.HostToolProvider = (*testTool)(nil)
diff --git a/java/builder.go b/java/builder.go
index d8b303e..ce9a5ee 100644
--- a/java/builder.go
+++ b/java/builder.go
@@ -133,7 +133,7 @@
)
func init() {
- pctx.Import("android/soong/common")
+ pctx.Import("android/soong/android")
pctx.Import("android/soong/java/config")
}
@@ -153,10 +153,7 @@
kotlincFlags string
kotlincClasspath classpath
- protoFlags []string
- protoOutTypeFlag string // The flag itself: --java_out
- protoOutParams string // Parameters to that flag: --java_out=$protoOutParams:$outDir
- protoRoot bool
+ proto android.ProtoFlags
}
func TransformJavaToClasses(ctx android.ModuleContext, outputFile android.WritablePath, shardIdx int,
diff --git a/java/dexpreopt_bootjars_test.go b/java/dexpreopt_bootjars_test.go
index 141f7ba..cbb52f1 100644
--- a/java/dexpreopt_bootjars_test.go
+++ b/java/dexpreopt_bootjars_test.go
@@ -103,7 +103,7 @@
expectedOutputs[i] = filepath.Join(buildDir, "test_device", expectedOutputs[i])
}
- outputs := bootArt.Outputs.Strings()
+ outputs := append(android.WritablePaths{bootArt.Output}, bootArt.ImplicitOutputs...).Strings()
sort.Strings(outputs)
sort.Strings(expectedOutputs)
diff --git a/java/gen.go b/java/gen.go
index 8362556..500d887 100644
--- a/java/gen.go
+++ b/java/gen.go
@@ -118,7 +118,7 @@
javaFile := genLogtags(ctx, srcFile)
outSrcFiles = append(outSrcFiles, javaFile)
case ".proto":
- srcJarFile := genProto(ctx, srcFile, flags)
+ srcJarFile := genProto(ctx, srcFile, flags.proto)
outSrcFiles = append(outSrcFiles, srcJarFile)
case ".sysprop":
srcJarFile := genSysprop(ctx, srcFile)
diff --git a/java/hiddenapi_singleton.go b/java/hiddenapi_singleton.go
index 86531eb..9627dc6 100644
--- a/java/hiddenapi_singleton.go
+++ b/java/hiddenapi_singleton.go
@@ -159,9 +159,9 @@
for moduleList, pathList := range moduleListToPathList {
for i := range pathList {
if pathList[i] == nil {
+ pathList[i] = android.PathForOutput(ctx, "missing")
if ctx.Config().AllowMissingDependencies() {
missingDeps = append(missingDeps, (*moduleList)[i])
- pathList[i] = android.PathForOutput(ctx, "missing")
} else {
ctx.Errorf("failed to find dex jar path for module %q",
(*moduleList)[i])
@@ -236,6 +236,8 @@
android.PathForSource(ctx, "frameworks/base/config/hiddenapi-greylist-max-o.txt")).
FlagWithInput("--blacklist ",
android.PathForSource(ctx, "frameworks/base/config/hiddenapi-force-blacklist.txt")).
+ FlagWithInput("--greylist-packages ",
+ android.PathForSource(ctx, "frameworks/base/config/hiddenapi-greylist-packages.txt")).
FlagWithOutput("--output ", tempPath)
commitChangeForRestat(rule, tempPath, outputPath)
diff --git a/java/java.go b/java/java.go
index beee1a5..0417dee 100644
--- a/java/java.go
+++ b/java/java.go
@@ -481,6 +481,7 @@
{Mutator: "arch", Variation: ctx.Config().BuildOsCommonVariant},
}, pluginTag, j.properties.Plugins...)
+ android.ProtoDeps(ctx, &j.protoProperties)
if j.hasSrcExt(".proto") {
protoDeps(ctx, &j.protoProperties)
}
@@ -768,12 +769,6 @@
deps.classpath = append(deps.classpath, dep.Srcs()...)
deps.staticJars = append(deps.staticJars, dep.Srcs()...)
deps.staticHeaderJars = append(deps.staticHeaderJars, dep.Srcs()...)
- case android.DefaultsDepTag, android.SourceDepTag:
- // Nothing to do
- case publicApiFileTag, systemApiFileTag, testApiFileTag:
- // Nothing to do
- default:
- ctx.ModuleErrorf("dependency on genrule %q may only be in srcs, libs, or static_libs", otherName)
}
default:
switch tag {
diff --git a/java/java_test.go b/java/java_test.go
index 6cb4818..2546698 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -138,6 +138,9 @@
"prebuilts/sdk/17/public/android.jar": nil,
"prebuilts/sdk/17/public/framework.aidl": nil,
"prebuilts/sdk/17/system/android.jar": nil,
+ "prebuilts/sdk/25/public/android.jar": nil,
+ "prebuilts/sdk/25/public/framework.aidl": nil,
+ "prebuilts/sdk/25/system/android.jar": nil,
"prebuilts/sdk/current/core/android.jar": nil,
"prebuilts/sdk/current/public/android.jar": nil,
"prebuilts/sdk/current/public/framework.aidl": nil,
diff --git a/java/proto.go b/java/proto.go
index 8028039..37de1d2 100644
--- a/java/proto.go
+++ b/java/proto.go
@@ -15,108 +15,83 @@
package java
import (
- "strings"
-
- "github.com/google/blueprint"
-
"android/soong/android"
)
-func init() {
- pctx.HostBinToolVariable("protocCmd", "aprotoc")
- pctx.HostBinToolVariable("depFixCmd", "dep_fixer")
-}
-
-var (
- proto = pctx.AndroidStaticRule("protoc",
- blueprint.RuleParams{
- Command: `rm -rf $out.tmp && mkdir -p $out.tmp && ` +
- `$protocCmd $protoOut=$protoOutParams:$out.tmp --dependency_out=$out.d -I $protoBase $protoFlags $in && ` +
- `$depFixCmd $out.d && ` +
- `${config.SoongZipCmd} -jar -o $out -C $out.tmp -D $out.tmp && rm -rf $out.tmp`,
- CommandDeps: []string{
- "$protocCmd",
- "$depFixCmd",
- "${config.SoongZipCmd}",
- },
- Depfile: "${out}.d",
- Deps: blueprint.DepsGCC,
- }, "protoBase", "protoFlags", "protoOut", "protoOutParams")
-)
-
-func genProto(ctx android.ModuleContext, protoFile android.Path, flags javaBuilderFlags) android.Path {
+func genProto(ctx android.ModuleContext, protoFile android.Path, flags android.ProtoFlags) android.Path {
srcJarFile := android.GenPathWithExt(ctx, "proto", protoFile, "srcjar")
- var protoBase string
- if flags.protoRoot {
- protoBase = "."
- } else {
- protoBase = strings.TrimSuffix(protoFile.String(), protoFile.Rel())
- }
+ outDir := srcJarFile.ReplaceExtension(ctx, "tmp")
+ depFile := srcJarFile.ReplaceExtension(ctx, "srcjar.d")
- ctx.Build(pctx, android.BuildParams{
- Rule: proto,
- Description: "protoc " + protoFile.Rel(),
- Output: srcJarFile,
- Input: protoFile,
- Args: map[string]string{
- "protoBase": protoBase,
- "protoOut": flags.protoOutTypeFlag,
- "protoOutParams": flags.protoOutParams,
- "protoFlags": strings.Join(flags.protoFlags, " "),
- },
- })
+ rule := android.NewRuleBuilder()
+
+ rule.Command().Text("rm -rf").Flag(outDir.String())
+ rule.Command().Text("mkdir -p").Flag(outDir.String())
+
+ android.ProtoRule(ctx, rule, protoFile, flags, flags.Deps, outDir, depFile, nil)
+
+ // Proto generated java files have an unknown package name in the path, so package the entire output directory
+ // into a srcjar.
+ rule.Command().
+ Tool(ctx.Config().HostToolPath(ctx, "soong_zip")).
+ Flag("-jar").
+ FlagWithOutput("-o ", srcJarFile).
+ FlagWithArg("-C ", outDir.String()).
+ FlagWithArg("-D ", outDir.String())
+
+ rule.Command().Text("rm -rf").Flag(outDir.String())
+
+ rule.Build(pctx, ctx, "protoc_"+protoFile.Rel(), "protoc "+protoFile.Rel())
return srcJarFile
}
func protoDeps(ctx android.BottomUpMutatorContext, p *android.ProtoProperties) {
- switch String(p.Proto.Type) {
- case "micro":
- ctx.AddVariationDependencies(nil, staticLibTag, "libprotobuf-java-micro")
- case "nano":
- ctx.AddVariationDependencies(nil, staticLibTag, "libprotobuf-java-nano")
- case "lite", "":
- ctx.AddVariationDependencies(nil, staticLibTag, "libprotobuf-java-lite")
- case "full":
- if ctx.Host() {
- ctx.AddVariationDependencies(nil, staticLibTag, "libprotobuf-java-full")
- } else {
- ctx.PropertyErrorf("proto.type", "full java protos only supported on the host")
+ if String(p.Proto.Plugin) == "" {
+ switch String(p.Proto.Type) {
+ case "micro":
+ ctx.AddVariationDependencies(nil, staticLibTag, "libprotobuf-java-micro")
+ case "nano":
+ ctx.AddVariationDependencies(nil, staticLibTag, "libprotobuf-java-nano")
+ case "lite", "":
+ ctx.AddVariationDependencies(nil, staticLibTag, "libprotobuf-java-lite")
+ case "full":
+ if ctx.Host() {
+ ctx.AddVariationDependencies(nil, staticLibTag, "libprotobuf-java-full")
+ } else {
+ ctx.PropertyErrorf("proto.type", "full java protos only supported on the host")
+ }
+ default:
+ ctx.PropertyErrorf("proto.type", "unknown proto type %q",
+ String(p.Proto.Type))
}
- default:
- ctx.PropertyErrorf("proto.type", "unknown proto type %q",
- String(p.Proto.Type))
}
}
func protoFlags(ctx android.ModuleContext, j *CompilerProperties, p *android.ProtoProperties,
flags javaBuilderFlags) javaBuilderFlags {
- switch String(p.Proto.Type) {
- case "micro":
- flags.protoOutTypeFlag = "--javamicro_out"
- case "nano":
- flags.protoOutTypeFlag = "--javanano_out"
- case "lite":
- flags.protoOutTypeFlag = "--java_out"
- flags.protoOutParams = "lite"
- case "full", "":
- flags.protoOutTypeFlag = "--java_out"
- default:
- ctx.PropertyErrorf("proto.type", "unknown proto type %q",
- String(p.Proto.Type))
- }
+ flags.proto = android.GetProtoFlags(ctx, p)
- if len(j.Proto.Output_params) > 0 {
- if flags.protoOutParams != "" {
- flags.protoOutParams += ","
+ if String(p.Proto.Plugin) == "" {
+ switch String(p.Proto.Type) {
+ case "micro":
+ flags.proto.OutTypeFlag = "--javamicro_out"
+ case "nano":
+ flags.proto.OutTypeFlag = "--javanano_out"
+ case "lite":
+ flags.proto.OutTypeFlag = "--java_out"
+ flags.proto.OutParams = append(flags.proto.OutParams, "lite")
+ case "full", "":
+ flags.proto.OutTypeFlag = "--java_out"
+ default:
+ ctx.PropertyErrorf("proto.type", "unknown proto type %q",
+ String(p.Proto.Type))
}
- flags.protoOutParams += strings.Join(j.Proto.Output_params, ",")
}
- flags.protoFlags = android.ProtoFlags(ctx, p)
- flags.protoRoot = android.ProtoCanonicalPathFromRoot(ctx, p)
+ flags.proto.OutParams = append(flags.proto.OutParams, j.Proto.Output_params...)
return flags
}
diff --git a/java/sdk.go b/java/sdk.go
index 0959be7..48e7746 100644
--- a/java/sdk.go
+++ b/java/sdk.go
@@ -84,7 +84,7 @@
v = strconv.Itoa(latestSdkVersion)
}
- i, err := sdkVersionToNumber(ctx, v)
+ numericSdkVersion, err := sdkVersionToNumber(ctx, v)
if err != nil {
ctx.PropertyErrorf("sdk_version", "%s", err)
return sdkDep{}
@@ -151,15 +151,14 @@
// Ensures that the specificed system SDK version is one of BOARD_SYSTEMSDK_VERSIONS (for vendor apks)
// or PRODUCT_SYSTEMSDK_VERSIONS (for other apks or when BOARD_SYSTEMSDK_VERSIONS is not set)
- if strings.HasPrefix(v, "system_") && i != android.FutureApiLevel {
+ if strings.HasPrefix(v, "system_") && numericSdkVersion != android.FutureApiLevel {
allowed_versions := ctx.DeviceConfig().PlatformSystemSdkVersions()
if ctx.DeviceSpecific() || ctx.SocSpecific() {
if len(ctx.DeviceConfig().SystemSdkVersions()) > 0 {
allowed_versions = ctx.DeviceConfig().SystemSdkVersions()
}
}
- version := strings.TrimPrefix(v, "system_")
- if len(allowed_versions) > 0 && !android.InList(version, allowed_versions) {
+ if len(allowed_versions) > 0 && !android.InList(strconv.Itoa(numericSdkVersion), allowed_versions) {
ctx.PropertyErrorf("sdk_version", "incompatible sdk version %q. System SDK version should be one of %q",
v, allowed_versions)
}
diff --git a/java/sdk_test.go b/java/sdk_test.go
index 6924e26..7fa40a3 100644
--- a/java/sdk_test.go
+++ b/java/sdk_test.go
@@ -50,11 +50,11 @@
},
{
- name: "sdk v14",
- properties: `sdk_version: "14",`,
+ name: "sdk v25",
+ properties: `sdk_version: "25",`,
bootclasspath: []string{`""`},
system: "bootclasspath", // special value to tell 1.9 test to expect bootclasspath
- classpath: []string{"prebuilts/sdk/14/public/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
+ classpath: []string{"prebuilts/sdk/25/public/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
},
{
@@ -72,11 +72,11 @@
},
{
- name: "system_14",
- properties: `sdk_version: "system_14",`,
+ name: "system_25",
+ properties: `sdk_version: "system_25",`,
bootclasspath: []string{`""`},
system: "bootclasspath", // special value to tell 1.9 test to expect bootclasspath
- classpath: []string{"prebuilts/sdk/14/system/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
+ classpath: []string{"prebuilts/sdk/25/system/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
},
{
@@ -140,12 +140,12 @@
},
{
- name: "unbundled sdk v14",
+ name: "unbundled sdk v25",
unbundled: true,
- properties: `sdk_version: "14",`,
+ properties: `sdk_version: "25",`,
bootclasspath: []string{`""`},
system: "bootclasspath", // special value to tell 1.9 test to expect bootclasspath
- classpath: []string{"prebuilts/sdk/14/public/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
+ classpath: []string{"prebuilts/sdk/25/public/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
},
{
@@ -162,7 +162,7 @@
pdk: true,
bootclasspath: []string{`""`},
system: "bootclasspath", // special value to tell 1.9 test to expect bootclasspath
- classpath: []string{"prebuilts/sdk/17/public/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
+ classpath: []string{"prebuilts/sdk/25/public/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
},
{
name: "pdk current",
@@ -170,15 +170,15 @@
properties: `sdk_version: "current",`,
bootclasspath: []string{`""`},
system: "bootclasspath", // special value to tell 1.9 test to expect bootclasspath
- classpath: []string{"prebuilts/sdk/17/public/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
+ classpath: []string{"prebuilts/sdk/25/public/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
},
{
- name: "pdk 14",
+ name: "pdk 25",
pdk: true,
- properties: `sdk_version: "14",`,
+ properties: `sdk_version: "25",`,
bootclasspath: []string{`""`},
system: "bootclasspath", // special value to tell 1.9 test to expect bootclasspath
- classpath: []string{"prebuilts/sdk/14/public/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
+ classpath: []string{"prebuilts/sdk/25/public/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
},
}
@@ -285,6 +285,44 @@
t.Errorf("bootclasspath expected %q != got %q", expected, got)
}
})
+
+ // Test again with PLATFORM_VERSION_CODENAME=REL
+ t.Run("REL", func(t *testing.T) {
+ config := testConfig(nil)
+ config.TestProductVariables.Platform_sdk_codename = proptools.StringPtr("REL")
+ config.TestProductVariables.Platform_sdk_final = proptools.BoolPtr(true)
+
+ if testcase.unbundled {
+ config.TestProductVariables.Unbundled_build = proptools.BoolPtr(true)
+ }
+ if testcase.pdk {
+ config.TestProductVariables.Pdk = proptools.BoolPtr(true)
+ }
+ ctx := testContext(config, bp, nil)
+ run(t, ctx, config)
+
+ javac := ctx.ModuleForTests("foo", variant).Rule("javac")
+
+ got := javac.Args["bootClasspath"]
+ if got != bc {
+ t.Errorf("bootclasspath expected %q != got %q", bc, got)
+ }
+
+ got = javac.Args["classpath"]
+ if got != c {
+ t.Errorf("classpath expected %q != got %q", c, got)
+ }
+
+ var deps []string
+ if len(bootclasspath) > 0 && bootclasspath[0] != `""` {
+ deps = append(deps, bootclasspath...)
+ }
+ deps = append(deps, classpath...)
+
+ if !reflect.DeepEqual(javac.Implicits.Strings(), deps) {
+ t.Errorf("implicits expected %q != got %q", deps, javac.Implicits.Strings())
+ }
+ })
})
}
diff --git a/java/testing.go b/java/testing.go
index 6febfa1..7d23d8f 100644
--- a/java/testing.go
+++ b/java/testing.go
@@ -28,7 +28,6 @@
env["ANDROID_JAVA8_HOME"] = "jdk8"
}
config := android.TestArchConfig(buildDir, env)
- config.TestProductVariables.DeviceSystemSdkVersions = []string{"14", "15"}
return config
}
diff --git a/phony/phony.go b/phony/phony.go
index e8a6550..ed6a2fe 100644
--- a/phony/phony.go
+++ b/phony/phony.go
@@ -34,7 +34,7 @@
func PhonyFactory() android.Module {
module := &phony{}
- android.InitAndroidModule(module)
+ android.InitAndroidArchModule(module, android.HostAndDeviceSupported, android.MultilibCommon)
return module
}
@@ -51,6 +51,9 @@
fmt.Fprintln(w, "\ninclude $(CLEAR_VARS)")
fmt.Fprintln(w, "LOCAL_PATH :=", moduleDir)
fmt.Fprintln(w, "LOCAL_MODULE :=", name)
+ if p.Host() {
+ fmt.Fprintln(w, "LOCAL_IS_HOST_MODULE := true")
+ }
fmt.Fprintln(w, "LOCAL_REQUIRED_MODULES := "+strings.Join(p.requiredModuleNames, " "))
fmt.Fprintln(w, "include $(BUILD_PHONY_PACKAGE)")
},
diff --git a/python/builder.go b/python/builder.go
index e3b490c..36baecd 100644
--- a/python/builder.go
+++ b/python/builder.go
@@ -73,7 +73,7 @@
func init() {
pctx.Import("github.com/google/blueprint/bootstrap")
- pctx.Import("android/soong/common")
+ pctx.Import("android/soong/android")
pctx.HostBinToolVariable("parCmd", "soong_zip")
pctx.HostBinToolVariable("mergeParCmd", "merge_zips")
diff --git a/python/proto.go b/python/proto.go
index 2370cd2..b3ffaa6 100644
--- a/python/proto.go
+++ b/python/proto.go
@@ -16,58 +16,35 @@
import (
"android/soong/android"
- "strings"
-
- "github.com/google/blueprint"
)
-func init() {
- pctx.HostBinToolVariable("protocCmd", "aprotoc")
-}
+func genProto(ctx android.ModuleContext, protoFile android.Path, flags android.ProtoFlags, pkgPath string) android.Path {
+ srcsZipFile := android.PathForModuleGen(ctx, protoFile.Base()+".srcszip")
-var (
- proto = pctx.AndroidStaticRule("protoc",
- blueprint.RuleParams{
- Command: `rm -rf $out.tmp && mkdir -p $out.tmp && ` +
- `$protocCmd --python_out=$out.tmp --dependency_out=$out.d -I $protoBase $protoFlags $in && ` +
- `$parCmd -o $out $pkgPathArgs -C $out.tmp -D $out.tmp && rm -rf $out.tmp`,
- CommandDeps: []string{
- "$protocCmd",
- "$parCmd",
- },
- Depfile: "${out}.d",
- Deps: blueprint.DepsGCC,
- }, "protoBase", "protoFlags", "pkgPathArgs")
-)
+ outDir := srcsZipFile.ReplaceExtension(ctx, "tmp")
+ depFile := srcsZipFile.ReplaceExtension(ctx, "srcszip.d")
-func genProto(ctx android.ModuleContext, p *android.ProtoProperties,
- protoFile android.Path, protoFlags []string, pkgPath string) android.Path {
- srcJarFile := android.PathForModuleGen(ctx, protoFile.Base()+".srcszip")
+ rule := android.NewRuleBuilder()
- protoRoot := android.ProtoCanonicalPathFromRoot(ctx, p)
+ rule.Command().Text("rm -rf").Flag(outDir.String())
+ rule.Command().Text("mkdir -p").Flag(outDir.String())
- var protoBase string
- if protoRoot {
- protoBase = "."
- } else {
- protoBase = strings.TrimSuffix(protoFile.String(), protoFile.Rel())
- }
+ android.ProtoRule(ctx, rule, protoFile, flags, flags.Deps, outDir, depFile, nil)
- var pkgPathArgs string
+ // Proto generated python files have an unknown package name in the path, so package the entire output directory
+ // into a srcszip.
+ zipCmd := rule.Command().
+ Tool(ctx.Config().HostToolPath(ctx, "soong_zip")).
+ FlagWithOutput("-o ", srcsZipFile).
+ FlagWithArg("-C ", outDir.String()).
+ FlagWithArg("-D ", outDir.String())
if pkgPath != "" {
- pkgPathArgs = "-P " + pkgPath
+ zipCmd.FlagWithArg("-P ", pkgPath)
}
- ctx.Build(pctx, android.BuildParams{
- Rule: proto,
- Description: "protoc " + protoFile.Rel(),
- Output: srcJarFile,
- Input: protoFile,
- Args: map[string]string{
- "protoBase": protoBase,
- "protoFlags": strings.Join(protoFlags, " "),
- "pkgPathArgs": pkgPathArgs,
- },
- })
- return srcJarFile
+ rule.Command().Text("rm -rf").Flag(outDir.String())
+
+ rule.Build(pctx, ctx, "protoc_"+protoFile.Rel(), "protoc "+protoFile.Rel())
+
+ return srcsZipFile
}
diff --git a/python/python.go b/python/python.go
index 6eb9b6e..ad08909 100644
--- a/python/python.go
+++ b/python/python.go
@@ -288,6 +288,8 @@
}
func (p *Module) DepsMutator(ctx android.BottomUpMutatorContext) {
+ android.ProtoDeps(ctx, &p.protoProperties)
+
if p.hasSrcExt(ctx, protoExt) && p.Name() != "libprotobuf-python" {
ctx.AddVariationDependencies(nil, pythonLibTag, "libprotobuf-python")
}
@@ -516,9 +518,11 @@
}
var zips android.Paths
if len(protoSrcs) > 0 {
+ protoFlags := android.GetProtoFlags(ctx, &p.protoProperties)
+ protoFlags.OutTypeFlag = "--python_out"
+
for _, srcFile := range protoSrcs {
- zip := genProto(ctx, &p.protoProperties, srcFile,
- android.ProtoFlags(ctx, &p.protoProperties), pkgPath)
+ zip := genProto(ctx, srcFile, protoFlags, pkgPath)
zips = append(zips, zip)
}
}