diff --git a/android/expand.go b/android/expand.go index 527c4ac6d..67fb4ee6e 100644 --- a/android/expand.go +++ b/android/expand.go @@ -18,12 +18,30 @@ import ( "fmt" "strings" "unicode" + + "github.com/google/blueprint/proptools" ) +// ExpandNinjaEscaped substitutes $() variables in a string +// $(var) is passed to mapping(var), which should return the expanded value, a bool for whether the result should +// be left unescaped when using in a ninja value (generally false, true if the expanded value is a ninja variable like +// '${in}'), and an error. +// $$ is converted to $, which is escaped back to $$. +func ExpandNinjaEscaped(s string, mapping func(string) (string, bool, error)) (string, error) { + return expand(s, true, mapping) +} + // Expand substitutes $() variables in a string -// $(var) is passed to Expander(var) -// $$ is converted to $ +// $(var) is passed to mapping(var), which should return the expanded value and an error. +// $$ is converted to $. func Expand(s string, mapping func(string) (string, error)) (string, error) { + return expand(s, false, func(s string) (string, bool, error) { + s, err := mapping(s) + return s, false, err + }) +} + +func expand(s string, ninjaEscape bool, mapping func(string) (string, bool, error)) (string, error) { // based on os.Expand buf := make([]byte, 0, 2*len(s)) i := 0 @@ -33,10 +51,13 @@ func Expand(s string, mapping func(string) (string, error)) (string, error) { return "", fmt.Errorf("expected character after '$'") } buf = append(buf, s[i:j]...) - value, w, err := getMapping(s[j+1:], mapping) + value, ninjaVariable, w, err := getMapping(s[j+1:], mapping) if err != nil { return "", err } + if !ninjaVariable && ninjaEscape { + value = proptools.NinjaEscape(value) + } buf = append(buf, value...) j += w i = j + 1 @@ -45,26 +66,26 @@ func Expand(s string, mapping func(string) (string, error)) (string, error) { return string(buf) + s[i:], nil } -func getMapping(s string, mapping func(string) (string, error)) (string, int, error) { +func getMapping(s string, mapping func(string) (string, bool, error)) (string, bool, int, error) { switch s[0] { case '(': // Scan to closing brace for i := 1; i < len(s); i++ { if s[i] == ')' { - ret, err := mapping(strings.TrimSpace(s[1:i])) - return ret, i + 1, err + ret, ninjaVariable, err := mapping(strings.TrimSpace(s[1:i])) + return ret, ninjaVariable, i + 1, err } } - return "", len(s), fmt.Errorf("missing )") + return "", false, len(s), fmt.Errorf("missing )") case '$': - return "$$", 1, nil + return "$", false, 1, nil default: i := strings.IndexFunc(s, unicode.IsSpace) if i == 0 { - return "", 0, fmt.Errorf("unexpected character '%c' after '$'", s[0]) + return "", false, 0, fmt.Errorf("unexpected character '%c' after '$'", s[0]) } else if i == -1 { i = len(s) } - return "", 0, fmt.Errorf("expected '(' after '$', did you mean $(%s)?", s[:i]) + return "", false, 0, fmt.Errorf("expected '(' after '$', did you mean $(%s)?", s[:i]) } } diff --git a/android/expand_test.go b/android/expand_test.go index 128de8a4e..12179eddf 100644 --- a/android/expand_test.go +++ b/android/expand_test.go @@ -20,88 +20,111 @@ import ( ) var vars = map[string]string{ - "var1": "abc", - "var2": "", - "var3": "def", - "💩": "😃", + "var1": "abc", + "var2": "", + "var3": "def", + "💩": "😃", + "escape": "${in}", } -func expander(s string) (string, error) { +func expander(s string) (string, bool, error) { if val, ok := vars[s]; ok { - return val, nil + return val, s == "escape", nil } else { - return "", fmt.Errorf("unknown variable %q", s) + return "", false, fmt.Errorf("unknown variable %q", s) } } var expandTestCases = []struct { - in string - out string - err bool + in string + out string + out_escaped string + err bool }{ { - in: "$(var1)", - out: "abc", + in: "$(var1)", + out: "abc", + out_escaped: "abc", }, { - in: "$( var1 )", - out: "abc", + in: "$( var1 )", + out: "abc", + out_escaped: "abc", }, { - in: "def$(var1)", - out: "defabc", + in: "def$(var1)", + out: "defabc", + out_escaped: "defabc", }, { - in: "$(var1)def", - out: "abcdef", + in: "$(var1)def", + out: "abcdef", + out_escaped: "abcdef", }, { - in: "def$(var1)def", - out: "defabcdef", + in: "def$(var1)def", + out: "defabcdef", + out_escaped: "defabcdef", }, { - in: "$(var2)", - out: "", + in: "$(var2)", + out: "", + out_escaped: "", }, { - in: "def$(var2)", - out: "def", + in: "def$(var2)", + out: "def", + out_escaped: "def", }, { - in: "$(var2)def", - out: "def", + in: "$(var2)def", + out: "def", + out_escaped: "def", }, { - in: "def$(var2)def", - out: "defdef", + in: "def$(var2)def", + out: "defdef", + out_escaped: "defdef", }, { - in: "$(var1)$(var3)", - out: "abcdef", + in: "$(var1)$(var3)", + out: "abcdef", + out_escaped: "abcdef", }, { - in: "$(var1)g$(var3)", - out: "abcgdef", + in: "$(var1)g$(var3)", + out: "abcgdef", + out_escaped: "abcgdef", }, { - in: "$$", - out: "$$", + in: "$$", + out: "$", + out_escaped: "$$", }, { - in: "$$(var1)", - out: "$$(var1)", + in: "$$(var1)", + out: "$(var1)", + out_escaped: "$$(var1)", }, { - in: "$$$(var1)", - out: "$$abc", + in: "$$$(var1)", + out: "$abc", + out_escaped: "$$abc", }, { - in: "$(var1)$$", - out: "abc$$", + in: "$(var1)$$", + out: "abc$", + out_escaped: "abc$$", }, { - in: "$(💩)", - out: "😃", + in: "$(💩)", + out: "😃", + out_escaped: "😃", + }, + { + in: "$$a$(escape)$$b", + out: "$a${in}$b", + out_escaped: "$$a${in}$$b", }, // Errors @@ -141,7 +164,10 @@ var expandTestCases = []struct { func TestExpand(t *testing.T) { for _, test := range expandTestCases { - got, err := Expand(test.in, expander) + got, err := Expand(test.in, func(s string) (string, error) { + s, _, err := expander(s) + return s, err + }) if err != nil && !test.err { t.Errorf("%q: unexpected error %s", test.in, err.Error()) } else if err == nil && test.err { @@ -151,3 +177,16 @@ func TestExpand(t *testing.T) { } } } + +func TestExpandNinjaEscaped(t *testing.T) { + for _, test := range expandTestCases { + got, err := ExpandNinjaEscaped(test.in, expander) + if err != nil && !test.err { + t.Errorf("%q: unexpected error %s", test.in, err.Error()) + } else if err == nil && test.err { + t.Errorf("%q: expected error, got %q", test.in, got) + } else if !test.err && got != test.out_escaped { + t.Errorf("%q: expected %q, got %q", test.in, test.out, got) + } + } +} diff --git a/android/proto.go b/android/proto.go index 5247c68dc..c8ade4564 100644 --- a/android/proto.go +++ b/android/proto.go @@ -135,7 +135,7 @@ func ProtoRule(ctx ModuleContext, rule *RuleBuilder, protoFile Path, flags Proto } rule.Command(). - Tool(ctx.Config().HostToolPath(ctx, "aprotoc")). + BuiltTool(ctx, "aprotoc"). FlagWithArg(flags.OutTypeFlag+"=", strings.Join(flags.OutParams, ",")+":"+outDir.String()). FlagWithDepFile("--dependency_out=", depFile). FlagWithArg("-I ", protoBase). @@ -145,5 +145,5 @@ func ProtoRule(ctx ModuleContext, rule *RuleBuilder, protoFile Path, flags Proto ImplicitOutputs(outputs) rule.Command(). - Tool(ctx.Config().HostToolPath(ctx, "dep_fixer")).Flag(depFile.String()) + BuiltTool(ctx, "dep_fixer").Flag(depFile.String()) } diff --git a/android/rule_builder.go b/android/rule_builder.go index e53eb0d2a..1238ddc6d 100644 --- a/android/rule_builder.go +++ b/android/rule_builder.go @@ -263,11 +263,36 @@ func (r *RuleBuilder) Tools() Paths { return toolsList } -// Commands returns a slice containing a the built command line for each call to RuleBuilder.Command. +// RspFileInputs returns the list of paths that were passed to the RuleBuilderCommand.FlagWithRspFileInputList method. +func (r *RuleBuilder) RspFileInputs() Paths { + var rspFileInputs Paths + for _, c := range r.commands { + if c.rspFileInputs != nil { + if rspFileInputs != nil { + panic("Multiple commands in a rule may not have rsp file inputs") + } + rspFileInputs = c.rspFileInputs + } + } + + return rspFileInputs +} + +// Commands returns a slice containing the built command line for each call to RuleBuilder.Command. func (r *RuleBuilder) Commands() []string { var commands []string for _, c := range r.commands { - commands = append(commands, c.buf.String()) + commands = append(commands, c.String()) + } + return commands +} + +// NinjaEscapedCommands returns a slice containin the built command line after ninja escaping for each call to +// RuleBuilder.Command. +func (r *RuleBuilder) NinjaEscapedCommands() []string { + var commands []string + for _, c := range r.commands { + commands = append(commands, c.NinjaEscapedString()) } return commands } @@ -284,7 +309,7 @@ var _ BuilderContext = SingletonContext(nil) func (r *RuleBuilder) depFileMergerCmd(ctx PathContext, depFiles WritablePaths) *RuleBuilderCommand { return r.Command(). - Tool(ctx.Config().HostToolPath(ctx, "dep_fixer")). + BuiltTool(ctx, "dep_fixer"). Inputs(depFiles.Paths()) } @@ -324,7 +349,7 @@ func (r *RuleBuilder) Build(pctx PackageContext, ctx BuilderContext, name string } tools := r.Tools() - commands := r.Commands() + commands := r.NinjaEscapedCommands() outputs := r.Outputs() if len(commands) == 0 { @@ -334,7 +359,7 @@ func (r *RuleBuilder) Build(pctx PackageContext, ctx BuilderContext, name string panic("No outputs specified from any Commands") } - commandString := strings.Join(proptools.NinjaEscapeList(commands), " && ") + commandString := strings.Join(commands, " && ") if r.sbox { sboxOutputs := make([]string, len(outputs)) @@ -352,7 +377,7 @@ func (r *RuleBuilder) Build(pctx PackageContext, ctx BuilderContext, name string } sboxCmd := &RuleBuilderCommand{} - sboxCmd.Tool(ctx.Config().HostToolPath(ctx, "sbox")). + sboxCmd.BuiltTool(ctx, "sbox"). Flag("-c").Text(commandString). Flag("--sandbox-path").Text(shared.TempDirForOutDir(PathForOutput(ctx).String())). Flag("--output-root").Text(r.sboxOutDir.String()). @@ -363,17 +388,27 @@ func (r *RuleBuilder) Build(pctx PackageContext, ctx BuilderContext, name string } // 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. + // ImplicitOutputs. RuleBuilder only uses "$out" for the rsp file location, so the distinction between Outputs and + // ImplicitOutputs doesn't matter. output := outputs[0] implicitOutputs := outputs[1:] + var rspFile, rspFileContent string + rspFileInputs := r.RspFileInputs() + if rspFileInputs != nil { + rspFile = "$out.rsp" + rspFileContent = "$in" + } + ctx.Build(pctx, BuildParams{ Rule: ctx.Rule(pctx, name, blueprint.RuleParams{ - Command: commandString, - CommandDeps: tools.Strings(), - Restat: r.restat, + Command: commandString, + CommandDeps: tools.Strings(), + Restat: r.restat, + Rspfile: rspFile, + RspfileContent: rspFileContent, }), + Inputs: rspFileInputs, Implicits: r.Inputs(), Output: output, ImplicitOutputs: implicitOutputs, @@ -388,11 +423,15 @@ func (r *RuleBuilder) Build(pctx PackageContext, ctx BuilderContext, name string // 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 strings.Builder - inputs Paths - outputs WritablePaths - depFiles WritablePaths - tools Paths + buf strings.Builder + inputs Paths + outputs WritablePaths + depFiles WritablePaths + tools Paths + rspFileInputs Paths + + // spans [start,end) of the command that should not be ninja escaped + unescapedSpans [][2]int sbox bool sboxOutDir WritablePath @@ -478,6 +517,24 @@ func (c *RuleBuilderCommand) Tool(path Path) *RuleBuilderCommand { return c.Text(path.String()) } +// BuiltTool adds the specified tool path that was built using a host Soong module to the command line. The path will +// be also added to the dependencies returned by RuleBuilder.Tools. +// +// It is equivalent to: +// cmd.Tool(ctx.Config().HostToolPath(ctx, tool)) +func (c *RuleBuilderCommand) BuiltTool(ctx PathContext, tool string) *RuleBuilderCommand { + return c.Tool(ctx.Config().HostToolPath(ctx, tool)) +} + +// PrebuiltBuildTool adds the specified tool path from prebuils/build-tools. The path will be also added to the +// dependencies returned by RuleBuilder.Tools. +// +// It is equivalent to: +// cmd.Tool(ctx.Config().PrebuiltBuildTool(ctx, tool)) +func (c *RuleBuilderCommand) PrebuiltBuildTool(ctx PathContext, tool string) *RuleBuilderCommand { + return c.Tool(ctx.Config().PrebuiltBuildTool(ctx, tool)) +} + // 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 { @@ -606,11 +663,56 @@ func (c *RuleBuilderCommand) FlagWithDepFile(flag string, path WritablePath) *Ru return c.Text(flag + c.outputStr(path)) } +// FlagWithRspFileInputList adds the specified flag and path to an rspfile to the command line, with no separator +// between them. The paths will be written to the rspfile. +func (c *RuleBuilderCommand) FlagWithRspFileInputList(flag string, paths Paths) *RuleBuilderCommand { + if c.rspFileInputs != nil { + panic("FlagWithRspFileInputList cannot be called if rsp file inputs have already been provided") + } + + // Use an empty slice if paths is nil, the non-nil slice is used as an indicator that the rsp file must be + // generated. + if paths == nil { + paths = Paths{} + } + + c.rspFileInputs = paths + + rspFile := "$out.rsp" + c.FlagWithArg(flag, rspFile) + c.unescapedSpans = append(c.unescapedSpans, [2]int{c.buf.Len() - len(rspFile), c.buf.Len()}) + return c +} + // String returns the command line. func (c *RuleBuilderCommand) String() string { return c.buf.String() } +// String returns the command line. +func (c *RuleBuilderCommand) NinjaEscapedString() string { + return ninjaEscapeExceptForSpans(c.String(), c.unescapedSpans) +} + +func ninjaEscapeExceptForSpans(s string, spans [][2]int) string { + if len(spans) == 0 { + return proptools.NinjaEscape(s) + } + + sb := strings.Builder{} + sb.Grow(len(s) * 11 / 10) + + i := 0 + for _, span := range spans { + sb.WriteString(proptools.NinjaEscape(s[i:span[0]])) + sb.WriteString(s[span[0]:span[1]]) + i = span[1] + } + sb.WriteString(proptools.NinjaEscape(s[i:])) + + return sb.String() +} + func ninjaNameEscape(s string) string { b := []byte(s) escaped := false diff --git a/android/rule_builder_test.go b/android/rule_builder_test.go index cfbc2abee..6eba4f127 100644 --- a/android/rule_builder_test.go +++ b/android/rule_builder_test.go @@ -38,6 +38,7 @@ func pathContext() PathContext { "ls": nil, "turbine": nil, "java": nil, + "javac": nil, }) } @@ -235,6 +236,34 @@ func ExampleRuleBuilderCommand_FlagWithList() { // ls --sort=time,size } +func ExampleRuleBuilderCommand_FlagWithRspFileInputList() { + ctx := pathContext() + fmt.Println(NewRuleBuilder().Command(). + Tool(PathForSource(ctx, "javac")). + FlagWithRspFileInputList("@", PathsForTesting("a.java", "b.java")). + NinjaEscapedString()) + // Output: + // javac @$out.rsp +} + +func ExampleRuleBuilderCommand_String() { + fmt.Println(NewRuleBuilder().Command(). + Text("FOO=foo"). + Text("echo $FOO"). + String()) + // Output: + // FOO=foo echo $FOO +} + +func ExampleRuleBuilderCommand_NinjaEscapedString() { + fmt.Println(NewRuleBuilder().Command(). + Text("FOO=foo"). + Text("echo $FOO"). + NinjaEscapedString()) + // Output: + // FOO=foo echo $$FOO +} + func TestRuleBuilder(t *testing.T) { fs := map[string][]byte{ "dep_fixer": nil, @@ -503,3 +532,77 @@ func TestRuleBuilder_Build(t *testing.T) { "cp bar "+outFile, outFile, outFile+".d", true, nil) }) } + +func Test_ninjaEscapeExceptForSpans(t *testing.T) { + type args struct { + s string + spans [][2]int + } + tests := []struct { + name string + args args + want string + }{ + { + name: "empty", + args: args{ + s: "", + }, + want: "", + }, + { + name: "unescape none", + args: args{ + s: "$abc", + }, + want: "$$abc", + }, + { + name: "unescape all", + args: args{ + s: "$abc", + spans: [][2]int{{0, 4}}, + }, + want: "$abc", + }, + { + name: "unescape first", + args: args{ + s: "$abc$", + spans: [][2]int{{0, 1}}, + }, + want: "$abc$$", + }, + { + name: "unescape last", + args: args{ + s: "$abc$", + spans: [][2]int{{4, 5}}, + }, + want: "$$abc$", + }, + { + name: "unescape middle", + args: args{ + s: "$a$b$c$", + spans: [][2]int{{2, 5}}, + }, + want: "$$a$b$c$$", + }, + { + name: "unescape multiple", + args: args{ + s: "$a$b$c$", + spans: [][2]int{{2, 3}, {4, 5}}, + }, + want: "$$a$b$c$$", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := ninjaEscapeExceptForSpans(tt.args.s, tt.args.spans); got != tt.want { + t.Errorf("ninjaEscapeExceptForSpans() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/cc/gen.go b/cc/gen.go index 7516b2877..e5c41945e 100644 --- a/cc/gen.go +++ b/cc/gen.go @@ -99,7 +99,7 @@ func genYacc(ctx android.ModuleContext, rule *android.RuleBuilder, yaccFile andr cmd.Text("BISON_PKGDATADIR=prebuilts/build-tools/common/bison"). FlagWithInput("M4=", ctx.Config().PrebuiltBuildTool(ctx, "m4")). - Tool(ctx.Config().PrebuiltBuildTool(ctx, "bison")). + PrebuiltBuildTool(ctx, "bison"). Flag("-d"). Flags(flags). FlagWithOutput("--defines=", headerFile). @@ -121,7 +121,7 @@ func genAidl(ctx android.ModuleContext, rule *android.RuleBuilder, aidlFile andr headerBp := outDir.Join(ctx, aidlPackage, "Bp"+shortName+".h") cmd := rule.Command() - cmd.Tool(ctx.Config().HostToolPath(ctx, "aidl-cpp")). + cmd.BuiltTool(ctx, "aidl-cpp"). FlagWithDepFile("-d", depFile). Flag("--ninja"). Flag(aidlFlags). diff --git a/cc/linker.go b/cc/linker.go index dda2fcb33..fa3b0a63d 100644 --- a/cc/linker.go +++ b/cc/linker.go @@ -483,7 +483,7 @@ func (linker *baseLinker) injectVersionSymbol(ctx ModuleContext, in android.Path Input: in, Output: out, Args: map[string]string{ - "buildNumberFromFile": ctx.Config().BuildNumberFromFile(), + "buildNumberFromFile": proptools.NinjaEscape(ctx.Config().BuildNumberFromFile()), }, }) } diff --git a/genrule/genrule.go b/genrule/genrule.go index b0657ff14..411da0522 100644 --- a/genrule/genrule.go +++ b/genrule/genrule.go @@ -284,12 +284,12 @@ func (g *Module) GenerateAndroidBuildActions(ctx android.ModuleContext) { referencedDepfile := false - rawCommand, err := android.Expand(task.cmd, func(name string) (string, error) { + rawCommand, err := android.ExpandNinjaEscaped(task.cmd, func(name string) (string, bool, error) { // report the error directly without returning an error to android.Expand to catch multiple errors in a // single run - reportError := func(fmt string, args ...interface{}) (string, error) { + reportError := func(fmt string, args ...interface{}) (string, bool, error) { ctx.PropertyErrorf("cmd", fmt, args...) - return "SOONG_ERROR", nil + return "SOONG_ERROR", false, nil } switch name { @@ -304,19 +304,19 @@ func (g *Module) GenerateAndroidBuildActions(ctx android.ModuleContext) { return reportError("default label %q has multiple files, use $(locations %s) to reference it", firstLabel, firstLabel) } - return locationLabels[firstLabel][0], nil + return locationLabels[firstLabel][0], false, nil case "in": - return "${in}", nil + return "${in}", true, nil case "out": - return "__SBOX_OUT_FILES__", nil + return "__SBOX_OUT_FILES__", false, nil case "depfile": referencedDepfile = true if !Bool(g.properties.Depfile) { return reportError("$(depfile) used without depfile property") } - return "__SBOX_DEPFILE__", nil + return "__SBOX_DEPFILE__", false, nil case "genDir": - return "__SBOX_OUT_DIR__", nil + return "__SBOX_OUT_DIR__", false, nil default: if strings.HasPrefix(name, "location ") { label := strings.TrimSpace(strings.TrimPrefix(name, "location ")) @@ -327,7 +327,7 @@ func (g *Module) GenerateAndroidBuildActions(ctx android.ModuleContext) { return reportError("label %q has multiple files, use $(locations %s) to reference it", label, label) } - return paths[0], nil + return paths[0], false, nil } else { return reportError("unknown location label %q", label) } @@ -337,7 +337,7 @@ func (g *Module) GenerateAndroidBuildActions(ctx android.ModuleContext) { if len(paths) == 0 { return reportError("label %q has no files", label) } - return strings.Join(paths, " "), nil + return strings.Join(paths, " "), false, nil } else { return reportError("unknown locations label %q", label) } diff --git a/java/app.go b/java/app.go index 344265851..a679e8823 100644 --- a/java/app.go +++ b/java/app.go @@ -816,7 +816,7 @@ func (a *AndroidAppImport) uncompressEmbeddedJniLibs( rule := android.NewRuleBuilder() rule.Command(). Textf(`if (zipinfo %s 'lib/*.so' 2>/dev/null | grep -v ' stor ' >/dev/null) ; then`, inputPath). - Tool(ctx.Config().HostToolPath(ctx, "zip2zip")). + BuiltTool(ctx, "zip2zip"). FlagWithInput("-i ", inputPath). FlagWithOutput("-o ", outputPath). FlagWithArg("-0 ", "'lib/**/*.so'"). @@ -843,7 +843,7 @@ func (a *AndroidAppImport) uncompressDex( rule := android.NewRuleBuilder() rule.Command(). Textf(`if (zipinfo %s '*.dex' 2>/dev/null | grep -v ' stor ' >/dev/null) ; then`, inputPath). - Tool(ctx.Config().HostToolPath(ctx, "zip2zip")). + BuiltTool(ctx, "zip2zip"). FlagWithInput("-i ", inputPath). FlagWithOutput("-o ", outputPath). FlagWithArg("-0 ", "'classes*.dex'"). @@ -1067,7 +1067,7 @@ func (u *usesLibrary) verifyUsesLibrariesManifest(ctx android.ModuleContext, man outputFile := android.PathForModuleOut(ctx, "manifest_check", "AndroidManifest.xml") rule := android.NewRuleBuilder() - cmd := rule.Command().Tool(ctx.Config().HostToolPath(ctx, "manifest_check")). + cmd := rule.Command().BuiltTool(ctx, "manifest_check"). Flag("--enforce-uses-libraries"). Input(manifest). FlagWithOutput("-o ", outputFile) diff --git a/java/dexpreopt_bootjars.go b/java/dexpreopt_bootjars.go index fe468a9e0..4ef5bcf4b 100644 --- a/java/dexpreopt_bootjars.go +++ b/java/dexpreopt_bootjars.go @@ -229,7 +229,7 @@ func buildBootImage(ctx android.SingletonContext, config bootImageConfig) *bootI if image.zip != nil { rule := android.NewRuleBuilder() rule.Command(). - Tool(ctx.Config().HostToolPath(ctx, "soong_zip")). + BuiltTool(ctx, "soong_zip"). FlagWithOutput("-o ", image.zip). FlagWithArg("-C ", image.dir.String()). FlagWithInputList("-f ", allFiles, " -f ") @@ -438,7 +438,7 @@ func dumpOatRules(ctx android.SingletonContext, image *bootImage) { rule := android.NewRuleBuilder() rule.Command(). // TODO: for now, use the debug version for better error reporting - Tool(ctx.Config().HostToolPath(ctx, "oatdumpd")). + BuiltTool(ctx, "oatdumpd"). FlagWithInputList("--runtime-arg -Xbootclasspath:", image.dexPaths.Paths(), ":"). FlagWithList("--runtime-arg -Xbootclasspath-locations:", image.dexLocations, ":"). FlagWithArg("--image=", dexpreopt.PathToLocation(image.images[arch], arch)).Implicit(image.images[arch]). diff --git a/java/droiddoc.go b/java/droiddoc.go index 25101de81..ae810e11c 100644 --- a/java/droiddoc.go +++ b/java/droiddoc.go @@ -500,6 +500,7 @@ func (j *Javadoc) OutputFiles(tag string) (android.Paths, error) { } } +// javadoc converts .java source files to documentation using javadoc. func JavadocFactory() android.Module { module := &Javadoc{} @@ -509,6 +510,7 @@ func JavadocFactory() android.Module { return module } +// javadoc_host converts .java source files to documentation using javadoc. func JavadocHostFactory() android.Module { module := &Javadoc{} @@ -798,7 +800,7 @@ func (j *Javadoc) GenerateAndroidBuildActions(ctx android.ModuleContext) { "srcJarDir": android.PathForModuleOut(ctx, "srcjars").String(), "stubsDir": android.PathForModuleOut(ctx, "stubsDir").String(), "srcJars": strings.Join(j.srcJars.Strings(), " "), - "opts": opts, + "opts": proptools.NinjaEscape(opts), "bootclasspathArgs": bootClasspathArgs, "classpathArgs": classpathArgs, "sourcepathArgs": sourcepathArgs, @@ -831,6 +833,7 @@ type Droiddoc struct { apiFilePath android.Path } +// droiddoc converts .java source files to documentation using doclava or dokka. func DroiddocFactory() android.Module { module := &Droiddoc{} @@ -841,6 +844,7 @@ func DroiddocFactory() android.Module { return module } +// droiddoc_host converts .java source files to documentation using doclava or dokka. func DroiddocHostFactory() android.Module { module := &Droiddoc{} @@ -918,7 +922,7 @@ func (d *Droiddoc) collectDoclavaDocsFlags(ctx android.ModuleContext, implicits args := " -source 1.8 -J-Xmx1600m -J-XX:-OmitStackTraceInFastThrow -XDignore.symbol.file " + "-doclet com.google.doclava.Doclava -docletpath " + jsilver.String() + ":" + doclava.String() + " " + "-hdf page.build " + ctx.Config().BuildId() + "-" + ctx.Config().BuildNumberFromFile() + " " + - `-hdf page.now "$$(` + date + ` @$$(cat ` + ctx.Config().Getenv("BUILD_DATETIME_FILE") + `) "+%d %b %Y %k:%M")" ` + `-hdf page.now "$(` + date + ` @$(cat ` + ctx.Config().Getenv("BUILD_DATETIME_FILE") + `) "+%d %b %Y %k:%M")" ` if String(d.properties.Custom_template) == "" { // TODO: This is almost always droiddoc-templates-sdk @@ -1095,7 +1099,7 @@ func (d *Droiddoc) transformDoclava(ctx android.ModuleContext, implicits android "srcJarDir": android.PathForModuleOut(ctx, "srcjars").String(), "stubsDir": android.PathForModuleOut(ctx, "stubsDir").String(), "srcJars": strings.Join(d.Javadoc.srcJars.Strings(), " "), - "opts": opts, + "opts": proptools.NinjaEscape(opts), "bootclasspathArgs": bootclasspathArgs, "classpathArgs": classpathArgs, "sourcepathArgs": sourcepathArgs, @@ -1117,7 +1121,7 @@ func (d *Droiddoc) transformCheckApi(ctx android.ModuleContext, apiFile, removed Args: map[string]string{ "msg": msg, "classpath": checkApiClasspath.FormJavaClassPath(""), - "opts": opts, + "opts": proptools.NinjaEscape(opts), "apiFile": apiFile.String(), "apiFileToCheck": d.apiFile.String(), "removedApiFile": removedApiFile.String(), @@ -1140,7 +1144,7 @@ func (d *Droiddoc) transformDokka(ctx android.ModuleContext, implicits android.P "stubsDir": android.PathForModuleOut(ctx, "dokka-stubsDir").String(), "srcJars": strings.Join(d.Javadoc.srcJars.Strings(), " "), "classpathArgs": classpathArgs, - "opts": opts, + "opts": proptools.NinjaEscape(opts), "docZip": d.Javadoc.docZip.String(), }, }) @@ -1258,6 +1262,9 @@ type Droidstubs struct { jdiffStubsSrcJar android.WritablePath } +// droidstubs passes sources files through Metalava to generate stub .java files that only contain the API to be +// documented, filtering out hidden classes and methods. The resulting .java files are intended to be passed to +// a droiddoc module to generate documentation. func DroidstubsFactory() android.Module { module := &Droidstubs{} @@ -1268,6 +1275,10 @@ func DroidstubsFactory() android.Module { return module } +// droidstubs_host passes sources files through Metalava to generate stub .java files that only contain the API +// to be documented, filtering out hidden classes and methods. The resulting .java files are intended to be +// passed to a droiddoc_host module to generate documentation. Use a droidstubs_host instead of a droidstubs +// module when symbols needed by the source files are provided by java_library_host modules. func DroidstubsHostFactory() android.Module { module := &Droidstubs{} @@ -1558,7 +1569,7 @@ func (d *Droidstubs) transformMetalava(ctx android.ModuleContext, implicits andr "bootclasspathArgs": bootclasspathArgs, "classpathArgs": classpathArgs, "sourcepathArgs": sourcepathArgs, - "opts": opts, + "opts": proptools.NinjaEscape(opts), }, }) } @@ -1581,7 +1592,7 @@ func (d *Droidstubs) transformCheckApi(ctx android.ModuleContext, "bootclasspathArgs": bootclasspathArgs, "classpathArgs": classpathArgs, "sourcepathArgs": sourcepathArgs, - "opts": opts, + "opts": proptools.NinjaEscape(opts), "msg": msg, }, }) @@ -1602,7 +1613,7 @@ func (d *Droidstubs) transformJdiff(ctx android.ModuleContext, implicits android "srcJarDir": android.PathForModuleOut(ctx, "jdiff-srcjars").String(), "stubsDir": android.PathForModuleOut(ctx, "jdiff-stubsDir").String(), "srcJars": strings.Join(d.Javadoc.srcJars.Strings(), " "), - "opts": opts, + "opts": proptools.NinjaEscape(opts), "bootclasspathArgs": bootclasspathArgs, "classpathArgs": classpathArgs, "sourcepathArgs": sourcepathArgs, @@ -1781,6 +1792,7 @@ type ExportedDroiddocDir struct { dir android.Path } +// droiddoc_exported_dir exports a directory of html templates or nullability annotations for use by doclava. func ExportedDroiddocDirFactory() android.Module { module := &ExportedDroiddocDir{} module.AddProperties(&module.properties) diff --git a/java/java.go b/java/java.go index f9ec27e24..a49aad775 100644 --- a/java/java.go +++ b/java/java.go @@ -2088,14 +2088,14 @@ func (j *DexImport) GenerateAndroidBuildActions(ctx android.ModuleContext) { // use zip2zip to uncompress classes*.dex files rule.Command(). - Tool(ctx.Config().HostToolPath(ctx, "zip2zip")). + BuiltTool(ctx, "zip2zip"). FlagWithInput("-i ", inputJar). FlagWithOutput("-o ", temporary). FlagWithArg("-0 ", "'classes*.dex'") // use zipalign to align uncompressed classes*.dex files rule.Command(). - Tool(ctx.Config().HostToolPath(ctx, "zipalign")). + BuiltTool(ctx, "zipalign"). Flag("-f"). Text("4"). Input(temporary). diff --git a/java/proto.go b/java/proto.go index 37de1d283..0ec64997e 100644 --- a/java/proto.go +++ b/java/proto.go @@ -34,7 +34,7 @@ func genProto(ctx android.ModuleContext, protoFile android.Path, flags android.P // 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")). + BuiltTool(ctx, "soong_zip"). Flag("-jar"). FlagWithOutput("-o ", srcJarFile). FlagWithArg("-C ", outDir.String()). diff --git a/java/sdk.go b/java/sdk.go index 7b79a49f2..d1e2ae4d1 100644 --- a/java/sdk.go +++ b/java/sdk.go @@ -296,7 +296,7 @@ func createSdkFrameworkAidl(ctx android.SingletonContext) { rule.Command(). Text("rm -f").Output(aidl) rule.Command(). - Tool(ctx.Config().HostToolPath(ctx, "sdkparcelables")). + BuiltTool(ctx, "sdkparcelables"). Input(jar). Output(aidl) diff --git a/python/proto.go b/python/proto.go index 85ed1a517..b71e047a5 100644 --- a/python/proto.go +++ b/python/proto.go @@ -34,7 +34,7 @@ func genProto(ctx android.ModuleContext, protoFile android.Path, flags android.P // 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")). + BuiltTool(ctx, "soong_zip"). FlagWithOutput("-o ", srcsZipFile) if pkgPath != "" { zipCmd.FlagWithArg("-P ", pkgPath) diff --git a/scripts/jar-wrapper.sh b/scripts/jar-wrapper.sh index 71c1d9067..b46804157 100644 --- a/scripts/jar-wrapper.sh +++ b/scripts/jar-wrapper.sh @@ -48,11 +48,11 @@ if [ ! -r "${jardir}/${jarfile}" ]; then exit 1 fi -javaOpts="" +declare -a javaOpts=() while expr "x$1" : 'x-J' >/dev/null; do - opt=`expr "$1" : '-J\(.*\)'` - javaOpts="${javaOpts} -${opt}" + opt=`expr "$1" : '-J-\{0,1\}\(.*\)'` + javaOpts+=("-${opt}") shift done -exec java ${javaOpts} -jar ${jardir}/${jarfile} "$@" +exec java "${javaOpts[@]}" -jar ${jardir}/${jarfile} "$@"