diff --git a/android/rule_builder.go b/android/rule_builder.go index 5edd7b65b..3b8694702 100644 --- a/android/rule_builder.go +++ b/android/rule_builder.go @@ -16,6 +16,7 @@ package android import ( "fmt" + "path/filepath" "sort" "strings" @@ -28,7 +29,7 @@ import ( type RuleBuilder struct { commands []*RuleBuilderCommand installs RuleBuilderInstalls - temporariesSet map[WritablePath]bool + temporariesSet map[string]bool restat bool missingDeps []string } @@ -36,14 +37,13 @@ type RuleBuilder struct { // NewRuleBuilder returns a newly created RuleBuilder. func NewRuleBuilder() *RuleBuilder { return &RuleBuilder{ - temporariesSet: make(map[WritablePath]bool), + temporariesSet: make(map[string]bool), } } // RuleBuilderInstall is a tuple of install from and to locations. type RuleBuilderInstall struct { - From Path - To string + From, To string } type RuleBuilderInstalls []RuleBuilderInstall @@ -56,7 +56,7 @@ func (installs RuleBuilderInstalls) String() string { if i != 0 { sb.WriteRune(' ') } - sb.WriteString(install.From.String()) + sb.WriteString(install.From) sb.WriteRune(':') sb.WriteString(install.To) } @@ -80,7 +80,7 @@ func (r *RuleBuilder) Restat() *RuleBuilder { // Install associates an output of the rule with an install location, which can be retrieved later using // RuleBuilder.Installs. -func (r *RuleBuilder) Install(from Path, to string) { +func (r *RuleBuilder) Install(from, to string) { r.installs = append(r.installs, RuleBuilderInstall{from, to}) } @@ -95,22 +95,19 @@ func (r *RuleBuilder) Command() *RuleBuilderCommand { // Temporary marks an output of a command as an intermediate file that will be used as an input to another command // in the same rule, and should not be listed in Outputs. -func (r *RuleBuilder) Temporary(path WritablePath) { +func (r *RuleBuilder) Temporary(path string) { r.temporariesSet[path] = true } // DeleteTemporaryFiles adds a command to the rule that deletes any outputs that have been marked using Temporary // when the rule runs. DeleteTemporaryFiles should be called after all calls to Temporary. func (r *RuleBuilder) DeleteTemporaryFiles() { - var temporariesList WritablePaths + var temporariesList []string for intermediate := range r.temporariesSet { temporariesList = append(temporariesList, intermediate) } - - sort.Slice(temporariesList, func(i, j int) bool { - return temporariesList[i].String() < temporariesList[j].String() - }) + sort.Strings(temporariesList) r.Command().Text("rm").Flag("-f").Outputs(temporariesList) } @@ -118,35 +115,32 @@ func (r *RuleBuilder) DeleteTemporaryFiles() { // Inputs returns the list of paths that were passed to the RuleBuilderCommand methods that take input paths, such // as RuleBuilderCommand.Input, RuleBuilderComand.Implicit, or RuleBuilderCommand.FlagWithInput. Inputs to a command // that are also outputs of another command in the same RuleBuilder are filtered out. -func (r *RuleBuilder) Inputs() Paths { +func (r *RuleBuilder) Inputs() []string { outputs := r.outputSet() - inputs := make(map[string]Path) + inputs := make(map[string]bool) for _, c := range r.commands { for _, input := range c.inputs { - if _, isOutput := outputs[input.String()]; !isOutput { - inputs[input.String()] = input + if !outputs[input] { + inputs[input] = true } } } - var inputList Paths - for _, input := range inputs { + var inputList []string + for input := range inputs { inputList = append(inputList, input) } - - sort.Slice(inputList, func(i, j int) bool { - return inputList[i].String() < inputList[j].String() - }) + sort.Strings(inputList) return inputList } -func (r *RuleBuilder) outputSet() map[string]WritablePath { - outputs := make(map[string]WritablePath) +func (r *RuleBuilder) outputSet() map[string]bool { + outputs := make(map[string]bool) for _, c := range r.commands { for _, output := range c.outputs { - outputs[output.String()] = output + outputs[output] = true } } return outputs @@ -154,20 +148,16 @@ func (r *RuleBuilder) outputSet() map[string]WritablePath { // Outputs returns the list of paths that were passed to the RuleBuilderCommand methods that take output paths, such // as RuleBuilderCommand.Output, RuleBuilderCommand.ImplicitOutput, or RuleBuilderCommand.FlagWithInput. -func (r *RuleBuilder) Outputs() WritablePaths { +func (r *RuleBuilder) Outputs() []string { outputs := r.outputSet() - var outputList WritablePaths - for _, output := range outputs { + var outputList []string + for output := range outputs { if !r.temporariesSet[output] { outputList = append(outputList, output) } } - - sort.Slice(outputList, func(i, j int) bool { - return outputList[i].String() < outputList[j].String() - }) - + sort.Strings(outputList) return outputList } @@ -176,11 +166,11 @@ func (r *RuleBuilder) Installs() RuleBuilderInstalls { return append(RuleBuilderInstalls(nil), r.installs...) } -func (r *RuleBuilder) toolsSet() map[string]Path { - tools := make(map[string]Path) +func (r *RuleBuilder) toolsSet() map[string]bool { + tools := make(map[string]bool) for _, c := range r.commands { for _, tool := range c.tools { - tools[tool.String()] = tool + tools[tool] = true } } @@ -188,18 +178,14 @@ func (r *RuleBuilder) toolsSet() map[string]Path { } // Tools returns the list of paths that were passed to the RuleBuilderCommand.Tool method. -func (r *RuleBuilder) Tools() Paths { +func (r *RuleBuilder) Tools() []string { toolsSet := r.toolsSet() - var toolsList Paths - for _, tool := range toolsSet { + var toolsList []string + for tool := range toolsSet { toolsList = append(toolsList, tool) } - - sort.Slice(toolsList, func(i, j int) bool { - return toolsList[i].String() < toolsList[j].String() - }) - + sort.Strings(toolsList) return toolsList } @@ -225,10 +211,45 @@ var _ BuilderContext = SingletonContext(nil) // 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) { + // TODO: convert RuleBuilder arguments and storage to Paths + mctx, _ := ctx.(ModuleContext) + var inputs Paths + for _, input := range r.Inputs() { + // Module output paths + if mctx != nil { + rel, isRel := MaybeRel(ctx, PathForModuleOut(mctx).String(), input) + if isRel { + inputs = append(inputs, PathForModuleOut(mctx, rel)) + continue + } + } + + // Other output paths + rel, isRel := MaybeRel(ctx, PathForOutput(ctx).String(), input) + if isRel { + inputs = append(inputs, PathForOutput(ctx, rel)) + continue + } + + // TODO: remove this once boot image is moved to where PathForOutput can find it. + inputs = append(inputs, &unknownRulePath{input}) + } + + var outputs WritablePaths + for _, output := range r.Outputs() { + if mctx != nil { + rel := Rel(ctx, PathForModuleOut(mctx).String(), output) + outputs = append(outputs, PathForModuleOut(mctx, rel)) + } else { + rel := Rel(ctx, PathForOutput(ctx).String(), output) + outputs = append(outputs, PathForOutput(ctx, rel)) + } + } + if len(r.missingDeps) > 0 { ctx.Build(pctx, BuildParams{ Rule: ErrorRule, - Outputs: r.Outputs(), + Outputs: outputs, Description: desc, Args: map[string]string{ "error": "missing dependencies: " + strings.Join(r.missingDeps, ", "), @@ -241,10 +262,10 @@ func (r *RuleBuilder) Build(pctx PackageContext, ctx BuilderContext, name string ctx.Build(pctx, BuildParams{ Rule: ctx.Rule(pctx, name, blueprint.RuleParams{ Command: strings.Join(proptools.NinjaEscape(r.Commands()), " && "), - CommandDeps: r.Tools().Strings(), + CommandDeps: r.Tools(), }), - Implicits: r.Inputs(), - Outputs: r.Outputs(), + Implicits: inputs, + Outputs: outputs, Description: desc, }) } @@ -256,9 +277,9 @@ func (r *RuleBuilder) Build(pctx PackageContext, ctx BuilderContext, name string // space as a separator from the previous method. type RuleBuilderCommand struct { buf []byte - inputs Paths - outputs WritablePaths - tools Paths + inputs []string + outputs []string + tools []string } // Text adds the specified raw text to the command line. The text should not contain input or output paths or the @@ -308,21 +329,21 @@ func (c *RuleBuilderCommand) FlagWithList(flag string, list []string, sep string // Tool adds the specified tool path to the command line. The path will be also added to the dependencies returned by // RuleBuilder.Tools. -func (c *RuleBuilderCommand) Tool(path Path) *RuleBuilderCommand { +func (c *RuleBuilderCommand) Tool(path string) *RuleBuilderCommand { c.tools = append(c.tools, path) - return c.Text(path.String()) + return c.Text(path) } // Input adds the specified input path to the command line. The path will also be added to the dependencies returned by // RuleBuilder.Inputs. -func (c *RuleBuilderCommand) Input(path Path) *RuleBuilderCommand { +func (c *RuleBuilderCommand) Input(path string) *RuleBuilderCommand { c.inputs = append(c.inputs, path) - return c.Text(path.String()) + return c.Text(path) } // Inputs adds the specified input paths to the command line, separated by spaces. The paths will also be added to the // dependencies returned by RuleBuilder.Inputs. -func (c *RuleBuilderCommand) Inputs(paths Paths) *RuleBuilderCommand { +func (c *RuleBuilderCommand) Inputs(paths []string) *RuleBuilderCommand { for _, path := range paths { c.Input(path) } @@ -331,28 +352,28 @@ func (c *RuleBuilderCommand) Inputs(paths Paths) *RuleBuilderCommand { // Implicit adds the specified input path to the dependencies returned by RuleBuilder.Inputs without modifying the // command line. -func (c *RuleBuilderCommand) Implicit(path Path) *RuleBuilderCommand { +func (c *RuleBuilderCommand) Implicit(path string) *RuleBuilderCommand { c.inputs = append(c.inputs, path) return c } // Implicits adds the specified input paths to the dependencies returned by RuleBuilder.Inputs without modifying the // command line. -func (c *RuleBuilderCommand) Implicits(paths Paths) *RuleBuilderCommand { +func (c *RuleBuilderCommand) Implicits(paths []string) *RuleBuilderCommand { c.inputs = append(c.inputs, paths...) return c } // Output adds the specified output path to the command line. The path will also be added to the outputs returned by // RuleBuilder.Outputs. -func (c *RuleBuilderCommand) Output(path WritablePath) *RuleBuilderCommand { +func (c *RuleBuilderCommand) Output(path string) *RuleBuilderCommand { c.outputs = append(c.outputs, path) - return c.Text(path.String()) + return c.Text(path) } // Outputs adds the specified output paths to the command line, separated by spaces. The paths will also be added to // the outputs returned by RuleBuilder.Outputs. -func (c *RuleBuilderCommand) Outputs(paths WritablePaths) *RuleBuilderCommand { +func (c *RuleBuilderCommand) Outputs(paths []string) *RuleBuilderCommand { for _, path := range paths { c.Output(path) } @@ -361,37 +382,37 @@ func (c *RuleBuilderCommand) Outputs(paths WritablePaths) *RuleBuilderCommand { // 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 { +func (c *RuleBuilderCommand) ImplicitOutput(path string) *RuleBuilderCommand { c.outputs = append(c.outputs, path) return c } // ImplicitOutputs adds the specified output paths to the dependencies returned by RuleBuilder.Outputs without modifying // the command line. -func (c *RuleBuilderCommand) ImplicitOutputs(paths WritablePaths) *RuleBuilderCommand { +func (c *RuleBuilderCommand) ImplicitOutputs(paths []string) *RuleBuilderCommand { c.outputs = append(c.outputs, paths...) 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 { +func (c *RuleBuilderCommand) FlagWithInput(flag, path string) *RuleBuilderCommand { c.inputs = append(c.inputs, path) - return c.Text(flag + path.String()) + return c.Text(flag + path) } // FlagWithInputList adds the specified flag and input paths to the command line, with the inputs joined by sep // and no separator between the flag and inputs. The input paths will also be added to the dependencies returned by // RuleBuilder.Inputs. -func (c *RuleBuilderCommand) FlagWithInputList(flag string, paths Paths, sep string) *RuleBuilderCommand { +func (c *RuleBuilderCommand) FlagWithInputList(flag string, paths []string, sep string) *RuleBuilderCommand { c.inputs = append(c.inputs, paths...) - return c.FlagWithList(flag, paths.Strings(), sep) + return c.FlagWithList(flag, paths, sep) } // FlagForEachInput adds the specified flag joined with each input path to the command line. The input paths will also // be added to the dependencies returned by RuleBuilder.Inputs. The result is identical to calling FlagWithInput for // each input path. -func (c *RuleBuilderCommand) FlagForEachInput(flag string, paths Paths) *RuleBuilderCommand { +func (c *RuleBuilderCommand) FlagForEachInput(flag string, paths []string) *RuleBuilderCommand { for _, path := range paths { c.FlagWithInput(flag, path) } @@ -400,12 +421,23 @@ func (c *RuleBuilderCommand) FlagForEachInput(flag string, paths Paths) *RuleBui // FlagWithOutput adds the specified flag and output 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) FlagWithOutput(flag string, path WritablePath) *RuleBuilderCommand { +func (c *RuleBuilderCommand) FlagWithOutput(flag, path string) *RuleBuilderCommand { c.outputs = append(c.outputs, path) - return c.Text(flag + path.String()) + return c.Text(flag + path) } // String returns the command line. func (c *RuleBuilderCommand) String() string { return string(c.buf) } + +type unknownRulePath struct { + path string +} + +var _ Path = (*unknownRulePath)(nil) + +func (p *unknownRulePath) String() string { return p.path } +func (p *unknownRulePath) Ext() string { return filepath.Ext(p.path) } +func (p *unknownRulePath) Base() string { return filepath.Base(p.path) } +func (p *unknownRulePath) Rel() string { return p.path } diff --git a/android/rule_builder_test.go b/android/rule_builder_test.go index f738fafcf..f94734898 100644 --- a/android/rule_builder_test.go +++ b/android/rule_builder_test.go @@ -24,30 +24,10 @@ import ( "testing" ) -func pathContext() PathContext { - return PathContextForTesting(TestConfig("out", nil), - map[string][]byte{ - "ld": nil, - "a.o": nil, - "b.o": nil, - "cp": nil, - "a": nil, - "b": nil, - "ls": nil, - "turbine": nil, - "java": nil, - }) -} - func ExampleRuleBuilder() { rule := NewRuleBuilder() - ctx := pathContext() - - rule.Command(). - Tool(PathForSource(ctx, "ld")). - Inputs(PathsForTesting("a.o", "b.o")). - FlagWithOutput("-o ", PathForOutput(ctx, "linked")) + rule.Command().Tool("ld").Inputs([]string{"a.o", "b.o"}).FlagWithOutput("-o ", "linked") rule.Command().Text("echo success") // To add the command to the build graph: @@ -59,26 +39,18 @@ func ExampleRuleBuilder() { fmt.Printf("outputs: %q\n", rule.Outputs()) // Output: - // commands: "ld a.o b.o -o out/linked && echo success" + // commands: "ld a.o b.o -o linked && echo success" // tools: ["ld"] // inputs: ["a.o" "b.o"] - // outputs: ["out/linked"] + // outputs: ["linked"] } func ExampleRuleBuilder_Temporary() { rule := NewRuleBuilder() - ctx := pathContext() - - rule.Command(). - Tool(PathForSource(ctx, "cp")). - Input(PathForSource(ctx, "a")). - Output(PathForOutput(ctx, "b")) - rule.Command(). - Tool(PathForSource(ctx, "cp")). - Input(PathForOutput(ctx, "b")). - Output(PathForOutput(ctx, "c")) - rule.Temporary(PathForOutput(ctx, "b")) + rule.Command().Tool("cp").Input("a").Output("b") + rule.Command().Tool("cp").Input("b").Output("c") + rule.Temporary("b") fmt.Printf("commands: %q\n", strings.Join(rule.Commands(), " && ")) fmt.Printf("tools: %q\n", rule.Tools()) @@ -86,26 +58,18 @@ func ExampleRuleBuilder_Temporary() { fmt.Printf("outputs: %q\n", rule.Outputs()) // Output: - // commands: "cp a out/b && cp out/b out/c" + // commands: "cp a b && cp b c" // tools: ["cp"] // inputs: ["a"] - // outputs: ["out/c"] + // outputs: ["c"] } func ExampleRuleBuilder_DeleteTemporaryFiles() { rule := NewRuleBuilder() - ctx := pathContext() - - rule.Command(). - Tool(PathForSource(ctx, "cp")). - Input(PathForSource(ctx, "a")). - Output(PathForOutput(ctx, "b")) - rule.Command(). - Tool(PathForSource(ctx, "cp")). - Input(PathForOutput(ctx, "b")). - Output(PathForOutput(ctx, "c")) - rule.Temporary(PathForOutput(ctx, "b")) + rule.Command().Tool("cp").Input("a").Output("b") + rule.Command().Tool("cp").Input("b").Output("c") + rule.Temporary("b") rule.DeleteTemporaryFiles() fmt.Printf("commands: %q\n", strings.Join(rule.Commands(), " && ")) @@ -114,112 +78,93 @@ func ExampleRuleBuilder_DeleteTemporaryFiles() { fmt.Printf("outputs: %q\n", rule.Outputs()) // Output: - // commands: "cp a out/b && cp out/b out/c && rm -f out/b" + // commands: "cp a b && cp b c && rm -f b" // tools: ["cp"] // inputs: ["a"] - // outputs: ["out/c"] + // outputs: ["c"] } func ExampleRuleBuilder_Installs() { rule := NewRuleBuilder() - ctx := pathContext() - - out := PathForOutput(ctx, "linked") - - rule.Command(). - Tool(PathForSource(ctx, "ld")). - Inputs(PathsForTesting("a.o", "b.o")). - FlagWithOutput("-o ", out) - rule.Install(out, "/bin/linked") - rule.Install(out, "/sbin/linked") + rule.Command().Tool("ld").Inputs([]string{"a.o", "b.o"}).FlagWithOutput("-o ", "linked") + rule.Install("linked", "/bin/linked") + rule.Install("linked", "/sbin/linked") fmt.Printf("rule.Installs().String() = %q\n", rule.Installs().String()) // Output: - // rule.Installs().String() = "out/linked:/bin/linked out/linked:/sbin/linked" + // rule.Installs().String() = "linked:/bin/linked linked:/sbin/linked" } func ExampleRuleBuilderCommand() { rule := NewRuleBuilder() - ctx := pathContext() - // chained - rule.Command(). - Tool(PathForSource(ctx, "ld")). - Inputs(PathsForTesting("a.o", "b.o")). - FlagWithOutput("-o ", PathForOutput(ctx, "linked")) + rule.Command().Tool("ld").Inputs([]string{"a.o", "b.o"}).FlagWithOutput("-o ", "linked") // unchained cmd := rule.Command() - cmd.Tool(PathForSource(ctx, "ld")) - cmd.Inputs(PathsForTesting("a.o", "b.o")) - cmd.FlagWithOutput("-o ", PathForOutput(ctx, "linked")) + cmd.Tool("ld") + cmd.Inputs([]string{"a.o", "b.o"}) + cmd.FlagWithOutput("-o ", "linked") // mixed: - cmd = rule.Command().Tool(PathForSource(ctx, "ld")) - cmd.Inputs(PathsForTesting("a.o", "b.o")) - cmd.FlagWithOutput("-o ", PathForOutput(ctx, "linked")) + cmd = rule.Command().Tool("ld") + cmd.Inputs([]string{"a.o", "b.o"}) + cmd.FlagWithOutput("-o ", "linked") } func ExampleRuleBuilderCommand_Flag() { - ctx := pathContext() fmt.Println(NewRuleBuilder().Command(). - Tool(PathForSource(ctx, "ls")).Flag("-l")) + Tool("ls").Flag("-l")) // Output: // ls -l } func ExampleRuleBuilderCommand_FlagWithArg() { - ctx := pathContext() fmt.Println(NewRuleBuilder().Command(). - Tool(PathForSource(ctx, "ls")). + Tool("ls"). FlagWithArg("--sort=", "time")) // Output: // ls --sort=time } func ExampleRuleBuilderCommand_FlagForEachArg() { - ctx := pathContext() fmt.Println(NewRuleBuilder().Command(). - Tool(PathForSource(ctx, "ls")). + Tool("ls"). FlagForEachArg("--sort=", []string{"time", "size"})) // Output: // ls --sort=time --sort=size } func ExampleRuleBuilderCommand_FlagForEachInput() { - ctx := pathContext() fmt.Println(NewRuleBuilder().Command(). - Tool(PathForSource(ctx, "turbine")). - FlagForEachInput("--classpath ", PathsForTesting("a.jar", "b.jar"))) + Tool("turbine"). + FlagForEachInput("--classpath ", []string{"a.jar", "b.jar"})) // Output: // turbine --classpath a.jar --classpath b.jar } func ExampleRuleBuilderCommand_FlagWithInputList() { - ctx := pathContext() fmt.Println(NewRuleBuilder().Command(). - Tool(PathForSource(ctx, "java")). - FlagWithInputList("-classpath=", PathsForTesting("a.jar", "b.jar"), ":")) + Tool("java"). + FlagWithInputList("-classpath=", []string{"a.jar", "b.jar"}, ":")) // Output: // java -classpath=a.jar:b.jar } func ExampleRuleBuilderCommand_FlagWithInput() { - ctx := pathContext() fmt.Println(NewRuleBuilder().Command(). - Tool(PathForSource(ctx, "java")). - FlagWithInput("-classpath=", PathForSource(ctx, "a"))) + Tool("java"). + FlagWithInput("-classpath=", "a")) // Output: // java -classpath=a } func ExampleRuleBuilderCommand_FlagWithList() { - ctx := pathContext() fmt.Println(NewRuleBuilder().Command(). - Tool(PathForSource(ctx, "ls")). + Tool("ls"). FlagWithList("--sort=", []string{"time", "size"}, ",")) // Output: // ls --sort=time,size @@ -228,35 +173,23 @@ func ExampleRuleBuilderCommand_FlagWithList() { func TestRuleBuilder(t *testing.T) { rule := NewRuleBuilder() - fs := map[string][]byte{ - "input": nil, - "Implicit": nil, - "Input": nil, - "Tool": nil, - "input2": nil, - "tool2": nil, - "input3": nil, - } - - ctx := PathContextForTesting(TestConfig("out", nil), fs) - cmd := rule.Command(). Flag("Flag"). FlagWithArg("FlagWithArg=", "arg"). - FlagWithInput("FlagWithInput=", PathForSource(ctx, "input")). - FlagWithOutput("FlagWithOutput=", PathForOutput(ctx, "output")). - Implicit(PathForSource(ctx, "Implicit")). - ImplicitOutput(PathForOutput(ctx, "ImplicitOutput")). - Input(PathForSource(ctx, "Input")). - Output(PathForOutput(ctx, "Output")). + FlagWithInput("FlagWithInput=", "input"). + FlagWithOutput("FlagWithOutput=", "output"). + Implicit("Implicit"). + ImplicitOutput("ImplicitOutput"). + Input("Input"). + Output("Output"). Text("Text"). - Tool(PathForSource(ctx, "Tool")) + Tool("Tool") rule.Command(). Text("command2"). - Input(PathForSource(ctx, "input2")). - Output(PathForOutput(ctx, "output2")). - Tool(PathForSource(ctx, "tool2")) + Input("input2"). + Output("output2"). + Tool("tool2") // Test updates to the first command after the second command has been started cmd.Text("after command2") @@ -266,18 +199,18 @@ func TestRuleBuilder(t *testing.T) { // Test a command that uses the output of a previous command as an input rule.Command(). Text("command3"). - Input(PathForSource(ctx, "input3")). - Input(PathForOutput(ctx, "output2")). - Output(PathForOutput(ctx, "output3")) + Input("input3"). + Input("output2"). + Output("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", - "command3 input3 out/output2 out/output3", + "Flag FlagWithArg=arg FlagWithInput=input FlagWithOutput=output Input Output Text Tool after command2 old cmd", + "command2 input2 output2 tool2", + "command3 input3 output2 output3", } - wantInputs := PathsForSource(ctx, []string{"Implicit", "Input", "input", "input2", "input3"}) - wantOutputs := PathsForOutput(ctx, []string{"ImplicitOutput", "Output", "output", "output2", "output3"}) - wantTools := PathsForSource(ctx, []string{"Tool", "tool2"}) + wantInputs := []string{"Implicit", "Input", "input", "input2", "input3"} + wantOutputs := []string{"ImplicitOutput", "Output", "output", "output2", "output3"} + wantTools := []string{"Tool", "tool2"} if !reflect.DeepEqual(rule.Commands(), wantCommands) { t.Errorf("\nwant rule.Commands() = %#v\n got %#v", wantCommands, rule.Commands()) @@ -329,7 +262,7 @@ func (t *testRuleBuilderSingleton) GenerateBuildActions(ctx SingletonContext) { func testRuleBuilder_Build(ctx BuilderContext, in Path, out WritablePath) { rule := NewRuleBuilder() - rule.Command().Tool(PathForSource(ctx, "cp")).Input(in).Output(out) + rule.Command().Tool("cp").Input(in.String()).Output(out.String()) rule.Build(pctx, ctx, "rule", "desc") } diff --git a/dexpreopt/config.go b/dexpreopt/config.go index 6f8ea3a1f..ee3cc8db0 100644 --- a/dexpreopt/config.go +++ b/dexpreopt/config.go @@ -17,7 +17,6 @@ package dexpreopt import ( "encoding/json" "io/ioutil" - "strings" "android/soong/android" ) @@ -75,13 +74,12 @@ type GlobalConfig struct { InstructionSetFeatures map[android.ArchType]string // instruction set for each architecture // Only used for boot image - DirtyImageObjects android.OptionalPath // path to a dirty-image-objects file - PreloadedClasses android.OptionalPath // path to a preloaded-classes file - BootImageProfiles android.Paths // path to a boot-image-profile.txt file - UseProfileForBootImage bool // whether a profile should be used to compile the boot image - BootFlags string // extra flags to pass to dex2oat for the boot image - Dex2oatImageXmx string // max heap size for dex2oat for the boot image - Dex2oatImageXms string // initial heap size for dex2oat for the boot image + DirtyImageObjects string // path to a dirty-image-objects file + PreloadedClasses string // path to a preloaded-classes file + BootImageProfiles []string // path to a boot-image-profile.txt file + BootFlags string // extra flags to pass to dex2oat for the boot image + Dex2oatImageXmx string // max heap size for dex2oat for the boot image + Dex2oatImageXms string // initial heap size for dex2oat for the boot image Tools Tools // paths to tools possibly used by the generated commands } @@ -89,38 +87,38 @@ type GlobalConfig struct { // Tools contains paths to tools possibly used by the generated commands. If you add a new tool here you MUST add it // to the order-only dependency list in DEXPREOPT_GEN_DEPS. type Tools struct { - Profman android.Path - Dex2oat android.Path - Aapt android.Path - SoongZip android.Path - Zip2zip android.Path + Profman string + Dex2oat string + Aapt string + SoongZip string + Zip2zip string - VerifyUsesLibraries android.Path - ConstructContext android.Path + VerifyUsesLibraries string + ConstructContext string } type ModuleConfig struct { Name string DexLocation string // dex location on device - BuildPath android.OutputPath - DexPath android.Path + BuildPath string + DexPath string UncompressedDex bool HasApkLibraries bool PreoptFlags []string - ProfileClassListing android.OptionalPath + ProfileClassListing string ProfileIsTextListing bool EnforceUsesLibraries bool OptionalUsesLibraries []string UsesLibraries []string - LibraryPaths map[string]android.Path + LibraryPaths map[string]string Archs []android.ArchType - DexPreoptImages []android.Path + DexPreoptImages []string - PreoptBootClassPathDexFiles android.Paths // file paths of boot class path files - PreoptBootClassPathDexLocations []string // virtual locations of boot class path files + PreoptBootClassPathDexFiles []string // file paths of boot class path files + PreoptBootClassPathDexLocations []string // virtual locations of boot class path files PreoptExtractedApk bool // Overrides OnlyPreoptModules @@ -130,137 +128,24 @@ type ModuleConfig struct { PresignedPrebuilt bool NoStripping bool - StripInputPath android.Path - StripOutputPath android.WritablePath + StripInputPath string + StripOutputPath string } -func constructPath(ctx android.PathContext, path string) android.Path { - buildDirPrefix := ctx.Config().BuildDir() + "/" - if path == "" { - return nil - } else if strings.HasPrefix(path, buildDirPrefix) { - return android.PathForOutput(ctx, strings.TrimPrefix(path, buildDirPrefix)) - } else { - return android.PathForSource(ctx, path) - } +func LoadGlobalConfig(path string) (GlobalConfig, error) { + config := GlobalConfig{} + err := loadConfig(path, &config) + return config, err } -func constructPaths(ctx android.PathContext, paths []string) android.Paths { - var ret android.Paths - for _, path := range paths { - ret = append(ret, constructPath(ctx, path)) - } - return ret +func LoadModuleConfig(path string) (ModuleConfig, error) { + config := ModuleConfig{} + err := loadConfig(path, &config) + return config, err } -func constructPathMap(ctx android.PathContext, paths map[string]string) map[string]android.Path { - ret := map[string]android.Path{} - for key, path := range paths { - ret[key] = constructPath(ctx, path) - } - return ret -} - -func constructWritablePath(ctx android.PathContext, path string) android.WritablePath { - if path == "" { - return nil - } - return constructPath(ctx, path).(android.WritablePath) -} - -// LoadGlobalConfig reads the global dexpreopt.config file into a GlobalConfig struct. It is used directly in Soong -// and in dexpreopt_gen called from Make to read the $OUT/dexpreopt.config written by Make. -func LoadGlobalConfig(ctx android.PathContext, path string) (GlobalConfig, error) { - type GlobalJSONConfig struct { - GlobalConfig - - // Copies of entries in GlobalConfig that are not constructable without extra parameters. They will be - // used to construct the real value manually below. - DirtyImageObjects string - PreloadedClasses string - BootImageProfiles []string - - Tools struct { - Profman string - Dex2oat string - Aapt string - SoongZip string - Zip2zip string - - VerifyUsesLibraries string - ConstructContext string - } - } - - config := GlobalJSONConfig{} - err := loadConfig(ctx, path, &config) - if err != nil { - return config.GlobalConfig, err - } - - // Construct paths that require a PathContext. - config.GlobalConfig.DirtyImageObjects = android.OptionalPathForPath(constructPath(ctx, config.DirtyImageObjects)) - config.GlobalConfig.PreloadedClasses = android.OptionalPathForPath(constructPath(ctx, config.PreloadedClasses)) - config.GlobalConfig.BootImageProfiles = constructPaths(ctx, config.BootImageProfiles) - - config.GlobalConfig.Tools.Profman = constructPath(ctx, config.Tools.Profman) - config.GlobalConfig.Tools.Dex2oat = constructPath(ctx, config.Tools.Dex2oat) - config.GlobalConfig.Tools.Aapt = constructPath(ctx, config.Tools.Aapt) - config.GlobalConfig.Tools.SoongZip = constructPath(ctx, config.Tools.SoongZip) - config.GlobalConfig.Tools.Zip2zip = constructPath(ctx, config.Tools.Zip2zip) - config.GlobalConfig.Tools.VerifyUsesLibraries = constructPath(ctx, config.Tools.VerifyUsesLibraries) - config.GlobalConfig.Tools.ConstructContext = constructPath(ctx, config.Tools.ConstructContext) - - return config.GlobalConfig, nil -} - -// LoadModuleConfig reads a per-module dexpreopt.config file into a ModuleConfig struct. It is not used in Soong, which -// receives a ModuleConfig struct directly from java/dexpreopt.go. It is used in dexpreopt_gen called from oMake to -// read the module dexpreopt.config written by Make. -func LoadModuleConfig(ctx android.PathContext, path string) (ModuleConfig, error) { - type ModuleJSONConfig struct { - ModuleConfig - - // Copies of entries in ModuleConfig that are not constructable without extra parameters. They will be - // used to construct the real value manually below. - BuildPath string - DexPath string - ProfileClassListing string - LibraryPaths map[string]string - DexPreoptImages []string - PreoptBootClassPathDexFiles []string - StripInputPath string - StripOutputPath string - } - - config := ModuleJSONConfig{} - - err := loadConfig(ctx, path, &config) - if err != nil { - return config.ModuleConfig, err - } - - // Construct paths that require a PathContext. - config.ModuleConfig.BuildPath = constructPath(ctx, config.BuildPath).(android.OutputPath) - config.ModuleConfig.DexPath = constructPath(ctx, config.DexPath) - config.ModuleConfig.ProfileClassListing = android.OptionalPathForPath(constructPath(ctx, config.ProfileClassListing)) - config.ModuleConfig.LibraryPaths = constructPathMap(ctx, config.LibraryPaths) - config.ModuleConfig.DexPreoptImages = constructPaths(ctx, config.DexPreoptImages) - config.ModuleConfig.PreoptBootClassPathDexFiles = constructPaths(ctx, config.PreoptBootClassPathDexFiles) - config.ModuleConfig.StripInputPath = constructPath(ctx, config.StripInputPath) - config.ModuleConfig.StripOutputPath = constructWritablePath(ctx, config.StripOutputPath) - - return config.ModuleConfig, nil -} - -func loadConfig(ctx android.PathContext, path string, config interface{}) error { - r, err := ctx.Fs().Open(path) - if err != nil { - return err - } - defer r.Close() - - data, err := ioutil.ReadAll(r) +func loadConfig(path string, config interface{}) error { + data, err := ioutil.ReadFile(path) if err != nil { return err } @@ -272,56 +157,3 @@ func loadConfig(ctx android.PathContext, path string, config interface{}) error return nil } - -func GlobalConfigForTests(ctx android.PathContext) GlobalConfig { - return GlobalConfig{ - DefaultNoStripping: false, - DisablePreoptModules: nil, - OnlyPreoptBootImageAndSystemServer: false, - HasSystemOther: false, - PatternsOnSystemOther: nil, - DisableGenerateProfile: false, - BootJars: nil, - RuntimeApexJars: nil, - ProductUpdatableBootModules: nil, - ProductUpdatableBootLocations: nil, - SystemServerJars: nil, - SystemServerApps: nil, - SpeedApps: nil, - PreoptFlags: nil, - DefaultCompilerFilter: "", - SystemServerCompilerFilter: "", - GenerateDMFiles: false, - NeverAllowStripping: false, - NoDebugInfo: false, - AlwaysSystemServerDebugInfo: false, - NeverSystemServerDebugInfo: false, - AlwaysOtherDebugInfo: false, - NeverOtherDebugInfo: false, - MissingUsesLibraries: nil, - IsEng: false, - SanitizeLite: false, - DefaultAppImages: false, - Dex2oatXmx: "", - Dex2oatXms: "", - EmptyDirectory: "empty_dir", - CpuVariant: nil, - InstructionSetFeatures: nil, - DirtyImageObjects: android.OptionalPath{}, - PreloadedClasses: android.OptionalPath{}, - BootImageProfiles: nil, - UseProfileForBootImage: false, - BootFlags: "", - Dex2oatImageXmx: "", - Dex2oatImageXms: "", - Tools: Tools{ - Profman: android.PathForTesting("profman"), - Dex2oat: android.PathForTesting("dex2oat"), - Aapt: android.PathForTesting("aapt"), - SoongZip: android.PathForTesting("soong_zip"), - Zip2zip: android.PathForTesting("zip2zip"), - VerifyUsesLibraries: android.PathForTesting("verify_uses_libraries.sh"), - ConstructContext: android.PathForTesting("construct_context.sh"), - }, - } -} diff --git a/dexpreopt/dexpreopt.go b/dexpreopt/dexpreopt.go index 9e333c108..7fdfb4969 100644 --- a/dexpreopt/dexpreopt.go +++ b/dexpreopt/dexpreopt.go @@ -37,7 +37,6 @@ package dexpreopt import ( "fmt" "path/filepath" - "runtime" "strings" "android/soong/android" @@ -53,9 +52,7 @@ const SystemOtherPartition = "/system_other/" func GenerateStripRule(global GlobalConfig, module ModuleConfig) (rule *android.RuleBuilder, err error) { defer func() { if r := recover(); r != nil { - if _, ok := r.(runtime.Error); ok { - panic(r) - } else if e, ok := r.(error); ok { + if e, ok := r.(error); ok { err = e rule = nil } else { @@ -89,14 +86,10 @@ func GenerateStripRule(global GlobalConfig, module ModuleConfig) (rule *android. // GenerateDexpreoptRule generates a set of commands that will preopt a module based on a GlobalConfig and a // ModuleConfig. The produced files and their install locations will be available through rule.Installs(). -func GenerateDexpreoptRule(ctx android.PathContext, - global GlobalConfig, module ModuleConfig) (rule *android.RuleBuilder, err error) { - +func GenerateDexpreoptRule(global GlobalConfig, module ModuleConfig) (rule *android.RuleBuilder, err error) { defer func() { if r := recover(); r != nil { - if _, ok := r.(runtime.Error); ok { - panic(r) - } else if e, ok := r.(error); ok { + if e, ok := r.(error); ok { err = e rule = nil } else { @@ -107,11 +100,11 @@ func GenerateDexpreoptRule(ctx android.PathContext, rule = android.NewRuleBuilder() - generateProfile := module.ProfileClassListing.Valid() && !global.DisableGenerateProfile + generateProfile := module.ProfileClassListing != "" && !global.DisableGenerateProfile - var profile android.WritablePath + var profile string if generateProfile { - profile = profileCommand(ctx, global, module, rule) + profile = profileCommand(global, module, rule) } if !dexpreoptDisabled(global, module) { @@ -125,7 +118,7 @@ func GenerateDexpreoptRule(ctx android.PathContext, for i, arch := range module.Archs { image := module.DexPreoptImages[i] - dexpreoptCommand(ctx, global, module, rule, arch, profile, image, appImage, generateDM) + dexpreoptCommand(global, module, rule, arch, profile, image, appImage, generateDM) } } } @@ -150,10 +143,8 @@ func dexpreoptDisabled(global GlobalConfig, module ModuleConfig) bool { return false } -func profileCommand(ctx android.PathContext, global GlobalConfig, module ModuleConfig, - rule *android.RuleBuilder) android.WritablePath { - - profilePath := module.BuildPath.InSameDir(ctx, "profile.prof") +func profileCommand(global GlobalConfig, module ModuleConfig, rule *android.RuleBuilder) string { + profilePath := filepath.Join(filepath.Dir(module.BuildPath), "profile.prof") profileInstalledPath := module.DexLocation + ".prof" if !module.ProfileIsTextListing { @@ -167,13 +158,13 @@ func profileCommand(ctx android.PathContext, global GlobalConfig, module ModuleC if module.ProfileIsTextListing { // The profile is a test listing of classes (used for framework jars). // We need to generate the actual binary profile before being able to compile. - cmd.FlagWithInput("--create-profile-from=", module.ProfileClassListing.Path()) + cmd.FlagWithInput("--create-profile-from=", module.ProfileClassListing) } else { // The profile is binary profile (used for apps). Run it through profman to // ensure the profile keys match the apk. cmd. Flag("--copy-and-update-profile-key"). - FlagWithInput("--profile-file=", module.ProfileClassListing.Path()) + FlagWithInput("--profile-file=", module.ProfileClassListing) } cmd. @@ -189,8 +180,8 @@ func profileCommand(ctx android.PathContext, global GlobalConfig, module ModuleC return profilePath } -func dexpreoptCommand(ctx android.PathContext, global GlobalConfig, module ModuleConfig, rule *android.RuleBuilder, - arch android.ArchType, profile, bootImage android.Path, appImage, generateDM bool) { +func dexpreoptCommand(global GlobalConfig, module ModuleConfig, rule *android.RuleBuilder, + arch android.ArchType, profile, bootImage string, appImage, generateDM bool) { // HACK: make soname in Soong-generated .odex files match Make. base := filepath.Base(module.DexLocation) @@ -208,21 +199,21 @@ func dexpreoptCommand(ctx android.PathContext, global GlobalConfig, module Modul pathtools.ReplaceExtension(filepath.Base(path), "odex")) } - odexPath := module.BuildPath.InSameDir(ctx, "oat", arch.String(), pathtools.ReplaceExtension(base, "odex")) + odexPath := toOdexPath(filepath.Join(filepath.Dir(module.BuildPath), base)) odexInstallPath := toOdexPath(module.DexLocation) if odexOnSystemOther(module, global) { odexInstallPath = strings.Replace(odexInstallPath, SystemPartition, SystemOtherPartition, 1) } - vdexPath := odexPath.ReplaceExtension(ctx, "vdex") + vdexPath := pathtools.ReplaceExtension(odexPath, "vdex") vdexInstallPath := pathtools.ReplaceExtension(odexInstallPath, "vdex") - invocationPath := odexPath.ReplaceExtension(ctx, "invocation") + invocationPath := pathtools.ReplaceExtension(odexPath, "invocation") // bootImage is .../dex_bootjars/system/framework/arm64/boot.art, but dex2oat wants // .../dex_bootjars/system/framework/boot.art on the command line var bootImageLocation string - if bootImage != nil { + if bootImage != "" { bootImageLocation = PathToLocation(bootImage, arch) } @@ -236,21 +227,19 @@ func dexpreoptCommand(ctx android.PathContext, global GlobalConfig, module Modul var filteredOptionalUsesLibs []string // The class loader context using paths in the build - var classLoaderContextHost android.Paths + var classLoaderContextHost []string // The class loader context using paths as they will be on the device var classLoaderContextTarget []string // Extra paths that will be appended to the class loader if the APK manifest has targetSdkVersion < 28 - var conditionalClassLoaderContextHost28 android.Paths + var conditionalClassLoaderContextHost28 []string var conditionalClassLoaderContextTarget28 []string // Extra paths that will be appended to the class loader if the APK manifest has targetSdkVersion < 29 - var conditionalClassLoaderContextHost29 android.Paths + var conditionalClassLoaderContextHost29 []string var conditionalClassLoaderContextTarget29 []string - var classLoaderContextHostString string - if module.EnforceUsesLibraries { verifyUsesLibs = copyOf(module.UsesLibraries) verifyOptionalUsesLibs = copyOf(module.OptionalUsesLibraries) @@ -292,41 +281,31 @@ func dexpreoptCommand(ctx android.PathContext, global GlobalConfig, module Modul pathForLibrary(module, hidlBase)) conditionalClassLoaderContextTarget29 = append(conditionalClassLoaderContextTarget29, filepath.Join("/system/framework", hidlBase+".jar")) - - classLoaderContextHostString = strings.Join(classLoaderContextHost.Strings(), ":") } else { // Pass special class loader context to skip the classpath and collision check. // This will get removed once LOCAL_USES_LIBRARIES is enforced. // Right now LOCAL_USES_LIBRARIES is opt in, for the case where it's not specified we still default // to the &. - classLoaderContextHostString = `\&` + classLoaderContextHost = []string{`\&`} } - rule.Command().FlagWithArg("mkdir -p ", filepath.Dir(odexPath.String())) + rule.Command().FlagWithArg("mkdir -p ", filepath.Dir(odexPath)) rule.Command().FlagWithOutput("rm -f ", odexPath) // Set values in the environment of the rule. These may be modified by construct_context.sh. - rule.Command().FlagWithArg("class_loader_context_arg=--class-loader-context=", classLoaderContextHostString) + rule.Command().FlagWithArg("class_loader_context_arg=--class-loader-context=", + strings.Join(classLoaderContextHost, ":")) rule.Command().Text(`stored_class_loader_context_arg=""`) if module.EnforceUsesLibraries { rule.Command().Textf(`uses_library_names="%s"`, strings.Join(verifyUsesLibs, " ")) rule.Command().Textf(`optional_uses_library_names="%s"`, strings.Join(verifyOptionalUsesLibs, " ")) rule.Command().Textf(`aapt_binary="%s"`, global.Tools.Aapt) - rule.Command().Textf(`dex_preopt_host_libraries="%s"`, - strings.Join(classLoaderContextHost.Strings(), " ")). - Implicits(classLoaderContextHost) - rule.Command().Textf(`dex_preopt_target_libraries="%s"`, - strings.Join(classLoaderContextTarget, " ")) - rule.Command().Textf(`conditional_host_libs_28="%s"`, - strings.Join(conditionalClassLoaderContextHost28.Strings(), " ")). - Implicits(conditionalClassLoaderContextHost28) - rule.Command().Textf(`conditional_target_libs_28="%s"`, - strings.Join(conditionalClassLoaderContextTarget28, " ")) - rule.Command().Textf(`conditional_host_libs_29="%s"`, - strings.Join(conditionalClassLoaderContextHost29.Strings(), " ")). - Implicits(conditionalClassLoaderContextHost29) - rule.Command().Textf(`conditional_target_libs_29="%s"`, - strings.Join(conditionalClassLoaderContextTarget29, " ")) + rule.Command().Textf(`dex_preopt_host_libraries="%s"`, strings.Join(classLoaderContextHost, " ")) + rule.Command().Textf(`dex_preopt_target_libraries="%s"`, strings.Join(classLoaderContextTarget, " ")) + rule.Command().Textf(`conditional_host_libs_28="%s"`, strings.Join(conditionalClassLoaderContextHost28, " ")) + rule.Command().Textf(`conditional_target_libs_28="%s"`, strings.Join(conditionalClassLoaderContextTarget28, " ")) + rule.Command().Textf(`conditional_host_libs_29="%s"`, strings.Join(conditionalClassLoaderContextHost29, " ")) + rule.Command().Textf(`conditional_target_libs_29="%s"`, strings.Join(conditionalClassLoaderContextTarget29, " ")) rule.Command().Text("source").Tool(global.Tools.VerifyUsesLibraries).Input(module.DexPath) rule.Command().Text("source").Tool(global.Tools.ConstructContext) } @@ -385,7 +364,7 @@ func dexpreoptCommand(ctx android.PathContext, global GlobalConfig, module Modul // Apps loaded into system server, and apps the product default to being compiled with the // 'speed' compiler filter. compilerFilter = "speed" - } else if profile != nil { + } else if profile != "" { // For non system server jars, use speed-profile when we have a profile. compilerFilter = "speed-profile" } else if global.DefaultCompilerFilter != "" { @@ -398,9 +377,9 @@ func dexpreoptCommand(ctx android.PathContext, global GlobalConfig, module Modul if generateDM { cmd.FlagWithArg("--copy-dex-files=", "false") - dmPath := module.BuildPath.InSameDir(ctx, "generated.dm") + dmPath := filepath.Join(filepath.Dir(module.BuildPath), "generated.dm") dmInstalledPath := pathtools.ReplaceExtension(module.DexLocation, "dm") - tmpPath := module.BuildPath.InSameDir(ctx, "primary.vdex") + tmpPath := filepath.Join(filepath.Dir(module.BuildPath), "primary.vdex") rule.Command().Text("cp -f").Input(vdexPath).Output(tmpPath) rule.Command().Tool(global.Tools.SoongZip). FlagWithArg("-L", "9"). @@ -449,15 +428,15 @@ func dexpreoptCommand(ctx android.PathContext, global GlobalConfig, module Modul cmd.FlagWithArg("--compilation-reason=", "prebuilt") if appImage { - appImagePath := odexPath.ReplaceExtension(ctx, "art") + appImagePath := pathtools.ReplaceExtension(odexPath, "art") appImageInstallPath := pathtools.ReplaceExtension(odexInstallPath, "art") cmd.FlagWithOutput("--app-image-file=", appImagePath). FlagWithArg("--image-format=", "lz4") rule.Install(appImagePath, appImageInstallPath) } - if profile != nil { - cmd.FlagWithInput("--profile-file=", profile) + if profile != "" { + cmd.FlagWithArg("--profile-file=", profile) } rule.Install(odexPath, odexInstallPath) @@ -543,17 +522,17 @@ func odexOnSystemOther(module ModuleConfig, global GlobalConfig) bool { } // PathToLocation converts .../system/framework/arm64/boot.art to .../system/framework/boot.art -func PathToLocation(path android.Path, arch android.ArchType) string { - pathArch := filepath.Base(filepath.Dir(path.String())) +func PathToLocation(path string, arch android.ArchType) string { + pathArch := filepath.Base(filepath.Dir(path)) if pathArch != arch.String() { panic(fmt.Errorf("last directory in %q must be %q", path, arch.String())) } - return filepath.Join(filepath.Dir(filepath.Dir(path.String())), filepath.Base(path.String())) + return filepath.Join(filepath.Dir(filepath.Dir(path)), filepath.Base(path)) } -func pathForLibrary(module ModuleConfig, lib string) android.Path { - path, ok := module.LibraryPaths[lib] - if !ok { +func pathForLibrary(module ModuleConfig, lib string) string { + path := module.LibraryPaths[lib] + if path == "" { panic(fmt.Errorf("unknown library path for %q", lib)) } return path diff --git a/dexpreopt/dexpreopt_gen/dexpreopt_gen.go b/dexpreopt/dexpreopt_gen/dexpreopt_gen.go index c72f6842d..cc3c1f10c 100644 --- a/dexpreopt/dexpreopt_gen/dexpreopt_gen.go +++ b/dexpreopt/dexpreopt_gen/dexpreopt_gen.go @@ -21,7 +21,6 @@ import ( "os" "path/filepath" "runtime" - "strings" "android/soong/android" "android/soong/dexpreopt" @@ -34,17 +33,8 @@ var ( stripScriptPath = flag.String("strip_script", "", "path to output strip script") globalConfigPath = flag.String("global", "", "path to global configuration file") moduleConfigPath = flag.String("module", "", "path to module configuration file") - outDir = flag.String("out_dir", "", "path to output directory") ) -type pathContext struct { - config android.Config -} - -func (x *pathContext) Fs() pathtools.FileSystem { return pathtools.OsFs } -func (x *pathContext) Config() android.Config { return x.config } -func (x *pathContext) AddNinjaFileDeps(...string) {} - func main() { flag.Parse() @@ -76,26 +66,18 @@ func main() { usage("path to module configuration file is required") } - ctx := &pathContext{android.TestConfig(*outDir, nil)} - - globalConfig, err := dexpreopt.LoadGlobalConfig(ctx, *globalConfigPath) + globalConfig, err := dexpreopt.LoadGlobalConfig(*globalConfigPath) if err != nil { fmt.Fprintf(os.Stderr, "error loading global config %q: %s\n", *globalConfigPath, err) os.Exit(2) } - moduleConfig, err := dexpreopt.LoadModuleConfig(ctx, *moduleConfigPath) + moduleConfig, err := dexpreopt.LoadModuleConfig(*moduleConfigPath) if err != nil { fmt.Fprintf(os.Stderr, "error loading module config %q: %s\n", *moduleConfigPath, err) os.Exit(2) } - // This shouldn't be using *PathForTesting, but it's outside of soong_build so its OK for now. - moduleConfig.StripInputPath = android.PathForTesting("$1") - moduleConfig.StripOutputPath = android.WritablePathForTesting("$2") - - moduleConfig.DexPath = android.PathForTesting("$1") - defer func() { if r := recover(); r != nil { switch x := r.(type) { @@ -110,30 +92,30 @@ func main() { } }() - writeScripts(ctx, globalConfig, moduleConfig, *dexpreoptScriptPath, *stripScriptPath) + writeScripts(globalConfig, moduleConfig, *dexpreoptScriptPath, *stripScriptPath) } -func writeScripts(ctx android.PathContext, global dexpreopt.GlobalConfig, module dexpreopt.ModuleConfig, +func writeScripts(global dexpreopt.GlobalConfig, module dexpreopt.ModuleConfig, dexpreoptScriptPath, stripScriptPath string) { - dexpreoptRule, err := dexpreopt.GenerateDexpreoptRule(ctx, global, module) + dexpreoptRule, err := dexpreopt.GenerateDexpreoptRule(global, module) if err != nil { panic(err) } - installDir := module.BuildPath.InSameDir(ctx, "dexpreopt_install") + installDir := filepath.Join(filepath.Dir(module.BuildPath), "dexpreopt_install") - dexpreoptRule.Command().FlagWithArg("rm -rf ", installDir.String()) - dexpreoptRule.Command().FlagWithArg("mkdir -p ", installDir.String()) + dexpreoptRule.Command().FlagWithArg("rm -rf ", installDir) + dexpreoptRule.Command().FlagWithArg("mkdir -p ", installDir) for _, install := range dexpreoptRule.Installs() { - installPath := installDir.Join(ctx, strings.TrimPrefix(install.To, "/")) - dexpreoptRule.Command().Text("mkdir -p").Flag(filepath.Dir(installPath.String())) + installPath := filepath.Join(installDir, install.To) + dexpreoptRule.Command().Text("mkdir -p").Flag(filepath.Dir(installPath)) dexpreoptRule.Command().Text("cp -f").Input(install.From).Output(installPath) } dexpreoptRule.Command().Tool(global.Tools.SoongZip). - FlagWithArg("-o ", "$2"). - FlagWithArg("-C ", installDir.String()). - FlagWithArg("-D ", installDir.String()) + FlagWithOutput("-o ", "$2"). + FlagWithArg("-C ", installDir). + FlagWithArg("-D ", installDir) stripRule, err := dexpreopt.GenerateStripRule(global, module) if err != nil { @@ -157,7 +139,7 @@ func writeScripts(ctx android.PathContext, global dexpreopt.GlobalConfig, module for _, input := range rule.Inputs() { // Assume the rule that ran the script already has a dependency on the input file passed on the // command line. - if input.String() != "$1" { + if input != "$1" { fmt.Fprintf(depFile, ` %s \`+"\n", input) } } @@ -177,13 +159,13 @@ func writeScripts(ctx android.PathContext, global dexpreopt.GlobalConfig, module } // The written scripts will assume the input is $1 and the output is $2 - if module.DexPath.String() != "$1" { + if module.DexPath != "$1" { panic(fmt.Errorf("module.DexPath must be '$1', was %q", module.DexPath)) } - if module.StripInputPath.String() != "$1" { + if module.StripInputPath != "$1" { panic(fmt.Errorf("module.StripInputPath must be '$1', was %q", module.StripInputPath)) } - if module.StripOutputPath.String() != "$2" { + if module.StripOutputPath != "$2" { panic(fmt.Errorf("module.StripOutputPath must be '$2', was %q", module.StripOutputPath)) } diff --git a/dexpreopt/dexpreopt_test.go b/dexpreopt/dexpreopt_test.go index 2a58ab9c6..949f91f3a 100644 --- a/dexpreopt/dexpreopt_test.go +++ b/dexpreopt/dexpreopt_test.go @@ -21,47 +21,98 @@ import ( "testing" ) -func testModuleConfig(ctx android.PathContext) ModuleConfig { - return ModuleConfig{ - Name: "test", - DexLocation: "/system/app/test/test.apk", - BuildPath: android.PathForOutput(ctx, "test/test.apk"), - DexPath: android.PathForOutput(ctx, "test/dex/test.jar"), - UncompressedDex: false, - HasApkLibraries: false, - PreoptFlags: nil, - ProfileClassListing: android.OptionalPath{}, - ProfileIsTextListing: false, - EnforceUsesLibraries: false, - OptionalUsesLibraries: nil, - UsesLibraries: nil, - LibraryPaths: nil, - Archs: []android.ArchType{android.Arm}, - DexPreoptImages: android.Paths{android.PathForTesting("system/framework/arm/boot.art")}, - PreoptBootClassPathDexFiles: nil, - PreoptBootClassPathDexLocations: nil, - PreoptExtractedApk: false, - NoCreateAppImage: false, - ForceCreateAppImage: false, - PresignedPrebuilt: false, - NoStripping: false, - StripInputPath: android.PathForOutput(ctx, "unstripped/test.apk"), - StripOutputPath: android.PathForOutput(ctx, "stripped/test.apk"), - } +var testGlobalConfig = GlobalConfig{ + DefaultNoStripping: false, + DisablePreoptModules: nil, + OnlyPreoptBootImageAndSystemServer: false, + HasSystemOther: false, + PatternsOnSystemOther: nil, + DisableGenerateProfile: false, + BootJars: nil, + RuntimeApexJars: nil, + ProductUpdatableBootModules: nil, + ProductUpdatableBootLocations: nil, + SystemServerJars: nil, + SystemServerApps: nil, + SpeedApps: nil, + PreoptFlags: nil, + DefaultCompilerFilter: "", + SystemServerCompilerFilter: "", + GenerateDMFiles: false, + NeverAllowStripping: false, + NoDebugInfo: false, + AlwaysSystemServerDebugInfo: false, + NeverSystemServerDebugInfo: false, + AlwaysOtherDebugInfo: false, + NeverOtherDebugInfo: false, + MissingUsesLibraries: nil, + IsEng: false, + SanitizeLite: false, + DefaultAppImages: false, + Dex2oatXmx: "", + Dex2oatXms: "", + EmptyDirectory: "", + CpuVariant: nil, + InstructionSetFeatures: nil, + DirtyImageObjects: "", + PreloadedClasses: "", + BootImageProfiles: nil, + BootFlags: "", + Dex2oatImageXmx: "", + Dex2oatImageXms: "", + Tools: Tools{ + Profman: "profman", + Dex2oat: "dex2oat", + Aapt: "aapt", + SoongZip: "soong_zip", + Zip2zip: "zip2zip", + VerifyUsesLibraries: "verify_uses_libraries.sh", + ConstructContext: "construct_context.sh", + }, +} + +var testModuleConfig = ModuleConfig{ + Name: "", + DexLocation: "", + BuildPath: "", + DexPath: "", + UncompressedDex: false, + HasApkLibraries: false, + PreoptFlags: nil, + ProfileClassListing: "", + ProfileIsTextListing: false, + EnforceUsesLibraries: false, + OptionalUsesLibraries: nil, + UsesLibraries: nil, + LibraryPaths: nil, + Archs: []android.ArchType{android.Arm}, + DexPreoptImages: []string{"system/framework/arm/boot.art"}, + PreoptBootClassPathDexFiles: nil, + PreoptBootClassPathDexLocations: nil, + PreoptExtractedApk: false, + NoCreateAppImage: false, + ForceCreateAppImage: false, + PresignedPrebuilt: false, + NoStripping: false, + StripInputPath: "", + StripOutputPath: "", } func TestDexPreopt(t *testing.T) { - ctx := android.PathContextForTesting(android.TestConfig("out", nil), nil) - global, module := GlobalConfigForTests(ctx), testModuleConfig(ctx) + global, module := testGlobalConfig, testModuleConfig - rule, err := GenerateDexpreoptRule(ctx, global, module) + module.Name = "test" + module.DexLocation = "/system/app/test/test.apk" + module.BuildPath = "out/test/test.apk" + + rule, err := GenerateDexpreoptRule(global, module) if err != nil { - t.Fatal(err) + t.Error(err) } wantInstalls := android.RuleBuilderInstalls{ - {android.PathForOutput(ctx, "test/oat/arm/package.odex"), "/system/app/test/oat/arm/test.odex"}, - {android.PathForOutput(ctx, "test/oat/arm/package.vdex"), "/system/app/test/oat/arm/test.vdex"}, + {"out/test/oat/arm/package.odex", "/system/app/test/oat/arm/test.odex"}, + {"out/test/oat/arm/package.vdex", "/system/app/test/oat/arm/test.vdex"}, } if !reflect.DeepEqual(rule.Installs(), wantInstalls) { @@ -71,11 +122,13 @@ func TestDexPreopt(t *testing.T) { func TestDexPreoptStrip(t *testing.T) { // Test that we panic if we strip in a configuration where stripping is not allowed. - ctx := android.PathContextForTesting(android.TestConfig("out", nil), nil) - global, module := GlobalConfigForTests(ctx), testModuleConfig(ctx) + global, module := testGlobalConfig, testModuleConfig global.NeverAllowStripping = true module.NoStripping = false + module.Name = "test" + module.DexLocation = "/system/app/test/test.apk" + module.BuildPath = "out/test/test.apk" _, err := GenerateStripRule(global, module) if err == nil { @@ -84,20 +137,23 @@ func TestDexPreoptStrip(t *testing.T) { } func TestDexPreoptSystemOther(t *testing.T) { - ctx := android.PathContextForTesting(android.TestConfig("out", nil), nil) - global, module := GlobalConfigForTests(ctx), testModuleConfig(ctx) + global, module := testGlobalConfig, testModuleConfig global.HasSystemOther = true global.PatternsOnSystemOther = []string{"app/%"} - rule, err := GenerateDexpreoptRule(ctx, global, module) + module.Name = "test" + module.DexLocation = "/system/app/test/test.apk" + module.BuildPath = "out/test/test.apk" + + rule, err := GenerateDexpreoptRule(global, module) if err != nil { - t.Fatal(err) + t.Error(err) } wantInstalls := android.RuleBuilderInstalls{ - {android.PathForOutput(ctx, "test/oat/arm/package.odex"), "/system_other/app/test/oat/arm/test.odex"}, - {android.PathForOutput(ctx, "test/oat/arm/package.vdex"), "/system_other/app/test/oat/arm/test.vdex"}, + {"out/test/oat/arm/package.odex", "/system_other/app/test/oat/arm/test.odex"}, + {"out/test/oat/arm/package.vdex", "/system_other/app/test/oat/arm/test.vdex"}, } if !reflect.DeepEqual(rule.Installs(), wantInstalls) { @@ -106,21 +162,23 @@ func TestDexPreoptSystemOther(t *testing.T) { } func TestDexPreoptProfile(t *testing.T) { - ctx := android.PathContextForTesting(android.TestConfig("out", nil), nil) - global, module := GlobalConfigForTests(ctx), testModuleConfig(ctx) + global, module := testGlobalConfig, testModuleConfig - module.ProfileClassListing = android.OptionalPathForPath(android.PathForTesting("profile")) + module.Name = "test" + module.DexLocation = "/system/app/test/test.apk" + module.BuildPath = "out/test/test.apk" + module.ProfileClassListing = "profile" - rule, err := GenerateDexpreoptRule(ctx, global, module) + rule, err := GenerateDexpreoptRule(global, module) if err != nil { - t.Fatal(err) + t.Error(err) } wantInstalls := android.RuleBuilderInstalls{ - {android.PathForOutput(ctx, "test/profile.prof"), "/system/app/test/test.apk.prof"}, - {android.PathForOutput(ctx, "test/oat/arm/package.art"), "/system/app/test/oat/arm/test.art"}, - {android.PathForOutput(ctx, "test/oat/arm/package.odex"), "/system/app/test/oat/arm/test.odex"}, - {android.PathForOutput(ctx, "test/oat/arm/package.vdex"), "/system/app/test/oat/arm/test.vdex"}, + {"out/test/profile.prof", "/system/app/test/test.apk.prof"}, + {"out/test/oat/arm/package.art", "/system/app/test/oat/arm/test.art"}, + {"out/test/oat/arm/package.odex", "/system/app/test/oat/arm/test.odex"}, + {"out/test/oat/arm/package.vdex", "/system/app/test/oat/arm/test.vdex"}, } if !reflect.DeepEqual(rule.Installs(), wantInstalls) { @@ -154,24 +212,29 @@ func TestStripDex(t *testing.T) { for _, test := range tests { t.Run(test.name, func(t *testing.T) { - ctx := android.PathContextForTesting(android.TestConfig("out", nil), nil) - global, module := GlobalConfigForTests(ctx), testModuleConfig(ctx) + global, module := testGlobalConfig, testModuleConfig + + module.Name = "test" + module.DexLocation = "/system/app/test/test.apk" + module.BuildPath = "out/test/test.apk" + module.StripInputPath = "$1" + module.StripOutputPath = "$2" test.setup(&global, &module) rule, err := GenerateStripRule(global, module) if err != nil { - t.Fatal(err) + t.Error(err) } if test.strip { - want := `zip2zip -i out/unstripped/test.apk -o out/stripped/test.apk -x "classes*.dex"` + want := `zip2zip -i $1 -o $2 -x "classes*.dex"` if len(rule.Commands()) < 1 || !strings.Contains(rule.Commands()[0], want) { t.Errorf("\nwant commands[0] to have:\n %v\ngot:\n %v", want, rule.Commands()[0]) } } else { wantCommands := []string{ - "cp -f out/unstripped/test.apk out/stripped/test.apk", + "cp -f $1 $2", } if !reflect.DeepEqual(rule.Commands(), wantCommands) { t.Errorf("\nwant commands:\n %v\ngot:\n %v", wantCommands, rule.Commands()) diff --git a/java/dexpreopt.go b/java/dexpreopt.go index b53e9c472..0a5652977 100644 --- a/java/dexpreopt.go +++ b/java/dexpreopt.go @@ -86,28 +86,18 @@ func (d *dexpreopter) dexpreoptDisabled(ctx android.ModuleContext) bool { } var dexpreoptGlobalConfigKey = android.NewOnceKey("DexpreoptGlobalConfig") -var dexpreoptTestGlobalConfigKey = android.NewOnceKey("TestDexpreoptGlobalConfig") - -func setDexpreoptGlobalConfig(config android.Config, globalConfig dexpreopt.GlobalConfig) { - config.Once(dexpreoptTestGlobalConfigKey, func() interface{} { return globalConfig }) -} func dexpreoptGlobalConfig(ctx android.PathContext) dexpreopt.GlobalConfig { return ctx.Config().Once(dexpreoptGlobalConfigKey, func() interface{} { if f := ctx.Config().DexpreoptGlobalConfig(); f != "" { ctx.AddNinjaFileDeps(f) - globalConfig, err := dexpreopt.LoadGlobalConfig(ctx, f) + globalConfig, err := dexpreopt.LoadGlobalConfig(f) if err != nil { panic(err) } return globalConfig } - - // No global config filename set, see if there is a test config set - return ctx.Config().Once(dexpreoptTestGlobalConfigKey, func() interface{} { - // Nope, return an empty config - return dexpreopt.GlobalConfig{} - }) + return dexpreopt.GlobalConfig{} }).(dexpreopt.GlobalConfig) } @@ -141,15 +131,17 @@ func (d *dexpreopter) dexpreopt(ctx android.ModuleContext, dexJarFile android.Mo archs = archs[:1] } - var images android.Paths + var images []string for _, arch := range archs { - images = append(images, info.images[arch]) + images = append(images, info.images[arch].String()) } dexLocation := android.InstallPathToOnDevicePath(ctx, d.installPath) strippedDexJarFile := android.PathForModuleOut(ctx, "dexpreopt", dexJarFile.Base()) + deps := android.Paths{dexJarFile} + var profileClassListing android.OptionalPath profileIsTextListing := false if BoolDefault(d.dexpreoptProperties.Dex_preopt.Profile_guided, true) { @@ -165,16 +157,20 @@ func (d *dexpreopter) dexpreopt(ctx android.ModuleContext, dexJarFile android.Mo } } + if profileClassListing.Valid() { + deps = append(deps, profileClassListing.Path()) + } + dexpreoptConfig := dexpreopt.ModuleConfig{ Name: ctx.ModuleName(), DexLocation: dexLocation, - BuildPath: android.PathForModuleOut(ctx, "dexpreopt", ctx.ModuleName()+".jar").OutputPath, - DexPath: dexJarFile, + BuildPath: android.PathForModuleOut(ctx, "dexpreopt", ctx.ModuleName()+".jar").String(), + DexPath: dexJarFile.String(), UncompressedDex: d.uncompressedDex, HasApkLibraries: false, PreoptFlags: nil, - ProfileClassListing: profileClassListing, + ProfileClassListing: profileClassListing.String(), ProfileIsTextListing: profileIsTextListing, EnforceUsesLibraries: false, @@ -185,7 +181,7 @@ func (d *dexpreopter) dexpreopt(ctx android.ModuleContext, dexJarFile android.Mo Archs: archs, DexPreoptImages: images, - PreoptBootClassPathDexFiles: info.preoptBootDex.Paths(), + PreoptBootClassPathDexFiles: info.preoptBootDex.Strings(), PreoptBootClassPathDexLocations: info.preoptBootLocations, PreoptExtractedApk: false, @@ -194,11 +190,11 @@ func (d *dexpreopter) dexpreopt(ctx android.ModuleContext, dexJarFile android.Mo ForceCreateAppImage: BoolDefault(d.dexpreoptProperties.Dex_preopt.App_image, false), NoStripping: Bool(d.dexpreoptProperties.Dex_preopt.No_stripping), - StripInputPath: dexJarFile, - StripOutputPath: strippedDexJarFile.OutputPath, + StripInputPath: dexJarFile.String(), + StripOutputPath: strippedDexJarFile.String(), } - dexpreoptRule, err := dexpreopt.GenerateDexpreoptRule(ctx, info.global, dexpreoptConfig) + dexpreoptRule, err := dexpreopt.GenerateDexpreoptRule(info.global, dexpreoptConfig) if err != nil { ctx.ModuleErrorf("error generating dexpreopt rule: %s", err.Error()) return dexJarFile diff --git a/java/dexpreopt_bootjars.go b/java/dexpreopt_bootjars.go index bb88d32ba..88534283b 100644 --- a/java/dexpreopt_bootjars.go +++ b/java/dexpreopt_bootjars.go @@ -259,7 +259,7 @@ func dexPreoptBootImageRule(ctx android.SingletonContext, info *bootJarsInfo, symbolsFile := symbolsDir.Join(ctx, "boot.oat") outputDir := info.dir.Join(ctx, "system/framework", arch.String()) outputPath := info.images[arch] - oatLocation := pathtools.ReplaceExtension(dexpreopt.PathToLocation(outputPath, arch), "oat") + oatLocation := pathtools.ReplaceExtension(dexpreopt.PathToLocation(outputPath.String(), arch), "oat") rule := android.NewRuleBuilder() rule.MissingDeps(missingDeps) @@ -289,31 +289,31 @@ func dexPreoptBootImageRule(ctx android.SingletonContext, info *bootJarsInfo, cmd.Tool(info.global.Tools.Dex2oat). Flag("--avoid-storing-invocation"). - FlagWithOutput("--write-invocation-to=", invocationPath).ImplicitOutput(invocationPath). + FlagWithOutput("--write-invocation-to=", invocationPath.String()).ImplicitOutput(invocationPath.String()). Flag("--runtime-arg").FlagWithArg("-Xms", info.global.Dex2oatImageXms). Flag("--runtime-arg").FlagWithArg("-Xmx", info.global.Dex2oatImageXmx) - if profile != nil { + if profile == nil { + cmd.FlagWithArg("--image-classes=", info.global.PreloadedClasses) + } else { cmd.FlagWithArg("--compiler-filter=", "speed-profile") - cmd.FlagWithInput("--profile-file=", profile) - } else if info.global.PreloadedClasses.Valid() { - cmd.FlagWithInput("--image-classes=", info.global.PreloadedClasses.Path()) + cmd.FlagWithInput("--profile-file=", profile.String()) } - if info.global.DirtyImageObjects.Valid() { - cmd.FlagWithInput("--dirty-image-objects=", info.global.DirtyImageObjects.Path()) + if info.global.DirtyImageObjects != "" { + cmd.FlagWithArg("--dirty-image-objects=", info.global.DirtyImageObjects) } cmd. - FlagForEachInput("--dex-file=", info.preoptBootDex.Paths()). + FlagForEachInput("--dex-file=", info.preoptBootDex.Strings()). FlagForEachArg("--dex-location=", info.preoptBootLocations). Flag("--generate-debug-info"). Flag("--generate-build-id"). - FlagWithOutput("--oat-symbols=", symbolsFile). + FlagWithArg("--oat-symbols=", symbolsFile.String()). Flag("--strip"). - FlagWithOutput("--oat-file=", outputPath.ReplaceExtension(ctx, "oat")). + FlagWithOutput("--oat-file=", outputPath.ReplaceExtension(ctx, "oat").String()). FlagWithArg("--oat-location=", oatLocation). - FlagWithOutput("--image=", outputPath). + FlagWithOutput("--image=", outputPath.String()). FlagWithArg("--base=", ctx.Config().LibartImgDeviceBaseAddress()). FlagWithArg("--instruction-set=", arch.String()). FlagWithArg("--instruction-set-variant=", info.global.CpuVariant[arch]). @@ -358,21 +358,21 @@ func dexPreoptBootImageRule(ctx android.SingletonContext, info *bootJarsInfo, extraFiles = append(extraFiles, art, oat, vdex, unstrippedOat) // Install the .oat and .art files. - rule.Install(art, filepath.Join(installDir, art.Base())) - rule.Install(oat, filepath.Join(installDir, oat.Base())) + rule.Install(art.String(), filepath.Join(installDir, art.Base())) + rule.Install(oat.String(), filepath.Join(installDir, oat.Base())) // The vdex files are identical between architectures, install them to a shared location. The Make rules will // only use the install rules for one architecture, and will create symlinks into the architecture-specific // directories. vdexInstalls = append(vdexInstalls, - android.RuleBuilderInstall{vdex, filepath.Join(vdexInstallDir, vdex.Base())}) + android.RuleBuilderInstall{vdex.String(), filepath.Join(vdexInstallDir, vdex.Base())}) // Install the unstripped oat files. The Make rules will put these in $(TARGET_OUT_UNSTRIPPED) unstrippedInstalls = append(unstrippedInstalls, - android.RuleBuilderInstall{unstrippedOat, filepath.Join(installDir, unstrippedOat.Base())}) + android.RuleBuilderInstall{unstrippedOat.String(), filepath.Join(installDir, unstrippedOat.Base())}) } - cmd.ImplicitOutputs(extraFiles) + cmd.ImplicitOutputs(extraFiles.Strings()) rule.Build(pctx, ctx, "bootJarsDexpreopt_"+arch.String(), "dexpreopt boot jars "+arch.String()) @@ -387,7 +387,7 @@ It is likely that the boot classpath is inconsistent. Rebuild with ART_BOOT_IMAGE_EXTRA_ARGS="--runtime-arg -verbose:verifier" to see verification errors.` func bootImageProfileRule(ctx android.SingletonContext, info *bootJarsInfo, missingDeps []string) android.WritablePath { - if !info.global.UseProfileForBootImage || ctx.Config().IsPdkBuild() || ctx.Config().UnbundledBuild() { + if len(info.global.BootImageProfiles) == 0 { return nil } @@ -396,25 +396,13 @@ func bootImageProfileRule(ctx android.SingletonContext, info *bootJarsInfo, miss rule := android.NewRuleBuilder() rule.MissingDeps(missingDeps) - var bootImageProfile android.Path + var bootImageProfile string if len(info.global.BootImageProfiles) > 1 { combinedBootImageProfile := info.dir.Join(ctx, "boot-image-profile.txt") - rule.Command().Text("cat").Inputs(info.global.BootImageProfiles).Text(">").Output(combinedBootImageProfile) - bootImageProfile = combinedBootImageProfile - } else if len(info.global.BootImageProfiles) == 1 { - bootImageProfile = info.global.BootImageProfiles[0] + rule.Command().Text("cat").Inputs(info.global.BootImageProfiles).Text(">").Output(combinedBootImageProfile.String()) + bootImageProfile = combinedBootImageProfile.String() } else { - // If not set, use the default. Some branches like master-art-host don't have frameworks/base, so manually - // handle the case that the default is missing. Those branches won't attempt to build the profile rule, - // and if they do they'll get a missing deps error. - defaultProfile := "frameworks/base/config/boot-image-profile.txt" - path := android.ExistentPathForSource(ctx, defaultProfile) - if path.Valid() { - bootImageProfile = path.Path() - } else { - missingDeps = append(missingDeps, defaultProfile) - bootImageProfile = android.PathForOutput(ctx, "missing") - } + bootImageProfile = info.global.BootImageProfiles[0] } profile := info.dir.Join(ctx, "boot.prof") @@ -422,12 +410,12 @@ func bootImageProfileRule(ctx android.SingletonContext, info *bootJarsInfo, miss rule.Command(). Text(`ANDROID_LOG_TAGS="*:e"`). Tool(tools.Profman). - FlagWithInput("--create-profile-from=", bootImageProfile). - FlagForEachInput("--apk=", info.preoptBootDex.Paths()). + FlagWithArg("--create-profile-from=", bootImageProfile). + FlagForEachInput("--apk=", info.preoptBootDex.Strings()). FlagForEachArg("--dex-location=", info.preoptBootLocations). - FlagWithOutput("--reference-profile-file=", profile) + FlagWithOutput("--reference-profile-file=", profile.String()) - rule.Install(profile, "/system/etc/boot-image.prof") + rule.Install(profile.String(), "/system/etc/boot-image.prof") rule.Build(pctx, ctx, "bootJarsProfile", "profile boot jars") @@ -451,6 +439,16 @@ func bootImageMakeVars(ctx android.MakeVarsContext) { for arch, _ := range info.images { ctx.Strict("DEXPREOPT_IMAGE_"+arch.String(), info.images[arch].String()) + var builtInstalled []string + for _, install := range info.installs[arch] { + builtInstalled = append(builtInstalled, install.From+":"+install.To) + } + + var unstrippedBuiltInstalled []string + for _, install := range info.unstrippedInstalls[arch] { + unstrippedBuiltInstalled = append(unstrippedBuiltInstalled, install.From+":"+install.To) + } + ctx.Strict("DEXPREOPT_IMAGE_BUILT_INSTALLED_"+arch.String(), info.installs[arch].String()) ctx.Strict("DEXPREOPT_IMAGE_UNSTRIPPED_BUILT_INSTALLED_"+arch.String(), info.unstrippedInstalls[arch].String()) ctx.Strict("DEXPREOPT_IMAGE_VDEX_BUILT_INSTALLED_"+arch.String(), info.vdexInstalls[arch].String()) diff --git a/java/hiddenapi.go b/java/hiddenapi.go index 104cd767b..01e2c5ec2 100644 --- a/java/hiddenapi.go +++ b/java/hiddenapi.go @@ -15,6 +15,8 @@ package java import ( + "path/filepath" + "github.com/google/blueprint" "android/soong/android" @@ -173,3 +175,14 @@ func hiddenAPIEncodeDex(ctx android.ModuleContext, output android.WritablePath, TransformZipAlign(ctx, output, tmpOutput) } } + +type hiddenAPIPath struct { + path string +} + +var _ android.Path = (*hiddenAPIPath)(nil) + +func (p *hiddenAPIPath) String() string { return p.path } +func (p *hiddenAPIPath) Ext() string { return filepath.Ext(p.path) } +func (p *hiddenAPIPath) Base() string { return filepath.Base(p.path) } +func (p *hiddenAPIPath) Rel() string { return p.path } diff --git a/java/hiddenapi_singleton.go b/java/hiddenapi_singleton.go index ba8b3e1f3..adbd35679 100644 --- a/java/hiddenapi_singleton.go +++ b/java/hiddenapi_singleton.go @@ -170,14 +170,14 @@ func stubFlagsRule(ctx android.SingletonContext) { rule.MissingDeps(missingDeps) rule.Command(). - Tool(pctx.HostBinToolPath(ctx, "hiddenapi")). + Tool(pctx.HostBinToolPath(ctx, "hiddenapi").String()). Text("list"). - FlagForEachInput("--boot-dex=", bootDexJars). - FlagWithInputList("--public-stub-classpath=", publicStubPaths, ":"). - FlagWithInputList("--public-stub-classpath=", systemStubPaths, ":"). - FlagWithInputList("--public-stub-classpath=", testStubPaths, ":"). - FlagWithInputList("--core-platform-stub-classpath=", corePlatformStubPaths, ":"). - FlagWithOutput("--out-api-flags=", tempPath) + FlagForEachInput("--boot-dex=", bootDexJars.Strings()). + FlagWithInputList("--public-stub-classpath=", publicStubPaths.Strings(), ":"). + FlagWithInputList("--public-stub-classpath=", systemStubPaths.Strings(), ":"). + FlagWithInputList("--public-stub-classpath=", testStubPaths.Strings(), ":"). + FlagWithInputList("--core-platform-stub-classpath=", corePlatformStubPaths.Strings(), ":"). + FlagWithOutput("--out-api-flags=", tempPath.String()) commitChangeForRestat(rule, tempPath, outputPath) @@ -214,20 +214,20 @@ func flagsRule(ctx android.SingletonContext) android.Path { stubFlags := hiddenAPISingletonPaths(ctx).stubFlags rule.Command(). - Tool(android.PathForSource(ctx, "frameworks/base/tools/hiddenapi/generate_hiddenapi_lists.py")). - FlagWithInput("--csv ", stubFlags). - Inputs(flagsCSV). + Tool(android.PathForSource(ctx, "frameworks/base/tools/hiddenapi/generate_hiddenapi_lists.py").String()). + FlagWithInput("--csv ", stubFlags.String()). + Inputs(flagsCSV.Strings()). FlagWithInput("--greylist ", - android.PathForSource(ctx, "frameworks/base/config/hiddenapi-greylist.txt")). + android.PathForSource(ctx, "frameworks/base/config/hiddenapi-greylist.txt").String()). FlagWithInput("--greylist-ignore-conflicts ", - greylistIgnoreConflicts). + greylistIgnoreConflicts.String()). FlagWithInput("--greylist-max-p ", - android.PathForSource(ctx, "frameworks/base/config/hiddenapi-greylist-max-p.txt")). + android.PathForSource(ctx, "frameworks/base/config/hiddenapi-greylist-max-p.txt").String()). FlagWithInput("--greylist-max-o-ignore-conflicts ", - android.PathForSource(ctx, "frameworks/base/config/hiddenapi-greylist-max-o.txt")). + android.PathForSource(ctx, "frameworks/base/config/hiddenapi-greylist-max-o.txt").String()). FlagWithInput("--blacklist ", - android.PathForSource(ctx, "frameworks/base/config/hiddenapi-force-blacklist.txt")). - FlagWithOutput("--output ", tempPath) + android.PathForSource(ctx, "frameworks/base/config/hiddenapi-force-blacklist.txt").String()). + FlagWithOutput("--output ", tempPath.String()) commitChangeForRestat(rule, tempPath, outputPath) @@ -243,8 +243,8 @@ func emptyFlagsRule(ctx android.SingletonContext) android.Path { outputPath := hiddenAPISingletonPaths(ctx).flags - rule.Command().Text("rm").Flag("-f").Output(outputPath) - rule.Command().Text("touch").Output(outputPath) + rule.Command().Text("rm").Flag("-f").Output(outputPath.String()) + rule.Command().Text("touch").Output(outputPath.String()) rule.Build(pctx, ctx, "emptyHiddenAPIFlagsFile", "empty hiddenapi flags") @@ -269,10 +269,10 @@ func metadataRule(ctx android.SingletonContext) android.Path { outputPath := hiddenAPISingletonPaths(ctx).metadata rule.Command(). - Tool(android.PathForSource(ctx, "frameworks/base/tools/hiddenapi/merge_csv.py")). - Inputs(metadataCSV). + Tool(android.PathForSource(ctx, "frameworks/base/tools/hiddenapi/merge_csv.py").String()). + Inputs(metadataCSV.Strings()). Text(">"). - Output(outputPath) + Output(outputPath.String()) rule.Build(pctx, ctx, "hiddenAPIGreylistMetadataFile", "hiddenapi greylist metadata") @@ -284,15 +284,15 @@ func metadataRule(ctx android.SingletonContext) android.Path { // the rule. func commitChangeForRestat(rule *android.RuleBuilder, tempPath, outputPath android.WritablePath) { rule.Restat() - rule.Temporary(tempPath) + rule.Temporary(tempPath.String()) rule.Command(). Text("("). Text("if"). - Text("cmp -s").Input(tempPath).Output(outputPath).Text(";"). + Text("cmp -s").Input(tempPath.String()).Output(outputPath.String()).Text(";"). Text("then"). - Text("rm").Input(tempPath).Text(";"). + Text("rm").Input(tempPath.String()).Text(";"). Text("else"). - Text("mv").Input(tempPath).Output(outputPath).Text(";"). + Text("mv").Input(tempPath.String()).Output(outputPath.String()).Text(";"). Text("fi"). Text(")") } diff --git a/java/testing.go b/java/testing.go index bec3c0b2c..6febfa1d3 100644 --- a/java/testing.go +++ b/java/testing.go @@ -18,7 +18,6 @@ import ( "fmt" "android/soong/android" - "android/soong/dexpreopt" ) func TestConfig(buildDir string, env map[string]string) android.Config { @@ -31,9 +30,6 @@ func TestConfig(buildDir string, env map[string]string) android.Config { config := android.TestArchConfig(buildDir, env) config.TestProductVariables.DeviceSystemSdkVersions = []string{"14", "15"} - pathCtx := android.PathContextForTesting(config, nil) - setDexpreoptGlobalConfig(config, dexpreopt.GlobalConfigForTests(pathCtx)) - return config }