Merge "Add USE_RBE support to soong."
diff --git a/Android.bp b/Android.bp
index 4893de6..62b0fd4 100644
--- a/Android.bp
+++ b/Android.bp
@@ -178,6 +178,7 @@
"cc/linker.go",
"cc/binary.go",
+ "cc/fuzz.go",
"cc/library.go",
"cc/object.go",
"cc/test.go",
diff --git a/android/expand.go b/android/expand.go
index 527c4ac..67fb4ee 100644
--- a/android/expand.go
+++ b/android/expand.go
@@ -18,12 +18,30 @@
"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 @@
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 @@
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 128de8a..12179ed 100644
--- a/android/expand_test.go
+++ b/android/expand_test.go
@@ -20,88 +20,111 @@
)
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 @@
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 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/neverallow.go b/android/neverallow.go
index 1893e8b..23b6454 100644
--- a/android/neverallow.go
+++ b/android/neverallow.go
@@ -48,6 +48,7 @@
var neverallows = []Rule{}
func init() {
+ AddNeverAllowRules(createIncludeDirsRules()...)
AddNeverAllowRules(createTrebleRules()...)
AddNeverAllowRules(createLibcoreRules()...)
AddNeverAllowRules(createJavaDeviceForHostRules()...)
@@ -58,6 +59,42 @@
neverallows = append(neverallows, rules...)
}
+func createIncludeDirsRules() []Rule {
+ // The list of paths that cannot be referenced using include_dirs
+ paths := []string{
+ "art",
+ "libcore",
+ "libnativehelper",
+ "external/apache-harmony",
+ "external/apache-xml",
+ "external/boringssl",
+ "external/bouncycastle",
+ "external/conscrypt",
+ "external/icu",
+ "external/okhttp",
+ "external/vixl",
+ "external/wycheproof",
+ "system/core/libnativebridge",
+ "system/core/libnativehelper",
+ }
+
+ // Create a composite matcher that will match if the value starts with any of the restricted
+ // paths. A / is appended to the prefix to ensure that restricting path X does not affect paths
+ // XY.
+ rules := make([]Rule, 0, len(paths))
+ for _, path := range paths {
+ rule :=
+ NeverAllow().
+ WithMatcher("include_dirs", StartsWith(path+"/")).
+ Because("include_dirs is deprecated, all usages of '" + path + "' have been migrated" +
+ " to use alternate mechanisms and so can no longer be used.")
+
+ rules = append(rules, rule)
+ }
+
+ return rules
+}
+
func createTrebleRules() []Rule {
return []Rule{
NeverAllow().
@@ -156,9 +193,51 @@
}
}
+type ValueMatcher interface {
+ test(string) bool
+ String() string
+}
+
+type equalMatcher struct {
+ expected string
+}
+
+func (m *equalMatcher) test(value string) bool {
+ return m.expected == value
+}
+
+func (m *equalMatcher) String() string {
+ return "=" + m.expected
+}
+
+type anyMatcher struct {
+}
+
+func (m *anyMatcher) test(value string) bool {
+ return true
+}
+
+func (m *anyMatcher) String() string {
+ return "=*"
+}
+
+var anyMatcherInstance = &anyMatcher{}
+
+type startsWithMatcher struct {
+ prefix string
+}
+
+func (m *startsWithMatcher) test(value string) bool {
+ return strings.HasPrefix(value, m.prefix)
+}
+
+func (m *startsWithMatcher) String() string {
+ return ".starts-with(" + m.prefix + ")"
+}
+
type ruleProperty struct {
- fields []string // e.x.: Vndk.Enabled
- value string // e.x.: true
+ fields []string // e.x.: Vndk.Enabled
+ matcher ValueMatcher
}
// A NeverAllow rule.
@@ -173,8 +252,12 @@
With(properties, value string) Rule
+ WithMatcher(properties string, matcher ValueMatcher) Rule
+
Without(properties, value string) Rule
+ WithoutMatcher(properties string, matcher ValueMatcher) Rule
+
Because(reason string) Rule
}
@@ -218,21 +301,36 @@
}
func (r *rule) With(properties, value string) Rule {
+ return r.WithMatcher(properties, selectMatcher(value))
+}
+
+func (r *rule) WithMatcher(properties string, matcher ValueMatcher) Rule {
r.props = append(r.props, ruleProperty{
- fields: fieldNamesForProperties(properties),
- value: value,
+ fields: fieldNamesForProperties(properties),
+ matcher: matcher,
})
return r
}
func (r *rule) Without(properties, value string) Rule {
+ return r.WithoutMatcher(properties, selectMatcher(value))
+}
+
+func (r *rule) WithoutMatcher(properties string, matcher ValueMatcher) Rule {
r.unlessProps = append(r.unlessProps, ruleProperty{
- fields: fieldNamesForProperties(properties),
- value: value,
+ fields: fieldNamesForProperties(properties),
+ matcher: matcher,
})
return r
}
+func selectMatcher(expected string) ValueMatcher {
+ if expected == "*" {
+ return anyMatcherInstance
+ }
+ return &equalMatcher{expected: expected}
+}
+
func (r *rule) Because(reason string) Rule {
r.reason = reason
return r
@@ -253,10 +351,10 @@
s += " -type:" + v
}
for _, v := range r.props {
- s += " " + strings.Join(v.fields, ".") + "=" + v.value
+ s += " " + strings.Join(v.fields, ".") + v.matcher.String()
}
for _, v := range r.unlessProps {
- s += " -" + strings.Join(v.fields, ".") + "=" + v.value
+ s += " -" + strings.Join(v.fields, ".") + v.matcher.String()
}
if len(r.reason) != 0 {
s += " which is restricted because " + r.reason
@@ -280,6 +378,10 @@
return includeProps && !excludeProps
}
+func StartsWith(prefix string) ValueMatcher {
+ return &startsWithMatcher{prefix}
+}
+
// assorted utils
func cleanPaths(paths []string) []string {
@@ -338,8 +440,8 @@
continue
}
- check := func(v string) bool {
- return prop.value == "*" || prop.value == v
+ check := func(value string) bool {
+ return prop.matcher.test(value)
}
if matchValue(propertiesValue, check) {
diff --git a/android/neverallow_test.go b/android/neverallow_test.go
index ee3c94f..02b4362 100644
--- a/android/neverallow_test.go
+++ b/android/neverallow_test.go
@@ -23,6 +23,29 @@
fs map[string][]byte
expectedError string
}{
+ // include_dir rule tests
+ {
+ name: "include_dir not allowed to reference art",
+ fs: map[string][]byte{
+ "other/Blueprints": []byte(`
+ cc_library {
+ name: "libother",
+ include_dirs: ["art/libdexfile/include"],
+ }`),
+ },
+ expectedError: "all usages of 'art' have been migrated",
+ },
+ {
+ name: "include_dir can reference another location",
+ fs: map[string][]byte{
+ "other/Blueprints": []byte(`
+ cc_library {
+ name: "libother",
+ include_dirs: ["another/include"],
+ }`),
+ },
+ },
+ // Treble rule tests
{
name: "no vndk.enabled under vendor directory",
fs: map[string][]byte{
@@ -217,6 +240,7 @@
}
type mockCcLibraryProperties struct {
+ Include_dirs []string
Vendor_available *bool
Vndk struct {
diff --git a/android/onceper.go b/android/onceper.go
index ff865c2..481cdea 100644
--- a/android/onceper.go
+++ b/android/onceper.go
@@ -95,6 +95,16 @@
return s[0], s[1]
}
+// OncePath is the same as Once, but returns the value cast to a Path
+func (once *OncePer) OncePath(key OnceKey, value func() Path) Path {
+ return once.Once(key, func() interface{} { return value() }).(Path)
+}
+
+// OncePath is the same as Once, but returns the value cast to a SourcePath
+func (once *OncePer) OnceSourcePath(key OnceKey, value func() SourcePath) SourcePath {
+ return once.Once(key, func() interface{} { return value() }).(SourcePath)
+}
+
// OnceKey is an opaque type to be used as the key in calls to Once.
type OnceKey struct {
key interface{}
diff --git a/android/path_properties.go b/android/path_properties.go
index af7af59..6b1cdb3 100644
--- a/android/path_properties.go
+++ b/android/path_properties.go
@@ -35,16 +35,17 @@
props := m.base().generalProperties
+ var pathProperties []string
for _, ps := range props {
- pathProperties := pathPropertiesForPropertyStruct(ctx, ps)
- pathProperties = FirstUniqueStrings(pathProperties)
+ pathProperties = append(pathProperties, pathPropertiesForPropertyStruct(ctx, ps)...)
+ }
- for _, s := range pathProperties {
- if m, t := SrcIsModuleWithTag(s); m != "" {
- ctx.AddDependency(ctx.Module(), sourceOrOutputDepTag(t), m)
- }
+ pathProperties = FirstUniqueStrings(pathProperties)
+
+ for _, s := range pathProperties {
+ if m, t := SrcIsModuleWithTag(s); m != "" {
+ ctx.AddDependency(ctx.Module(), sourceOrOutputDepTag(t), m)
}
-
}
}
diff --git a/android/path_properties_test.go b/android/path_properties_test.go
index e98c136..59bfa6c 100644
--- a/android/path_properties_test.go
+++ b/android/path_properties_test.go
@@ -28,12 +28,17 @@
Qux string
}
+ // A second property struct with a duplicate property name
+ props2 struct {
+ Foo string `android:"path"`
+ }
+
sourceDeps []string
}
func pathDepsMutatorTestModuleFactory() Module {
module := &pathDepsMutatorTestModule{}
- module.AddProperties(&module.props)
+ module.AddProperties(&module.props, &module.props2)
InitAndroidArchModule(module, DeviceSupported, MultilibBoth)
return module
}
@@ -44,6 +49,13 @@
p.sourceDeps = append(p.sourceDeps, ctx.OtherModuleName(dep))
}
})
+
+ if p.props.Foo != "" {
+ // Make sure there is only one dependency on a module listed in a property present in multiple property structs
+ if ctx.GetDirectDepWithTag(SrcIsModule(p.props.Foo), sourceOrOutputDepTag("")) == nil {
+ ctx.ModuleErrorf("GetDirectDepWithTag failed")
+ }
+ }
}
func TestPathDepsMutator(t *testing.T) {
diff --git a/android/proto.go b/android/proto.go
index 5247c68..c8ade45 100644
--- a/android/proto.go
+++ b/android/proto.go
@@ -135,7 +135,7 @@
}
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 @@
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 e53eb0d..48d070e 100644
--- a/android/rule_builder.go
+++ b/android/rule_builder.go
@@ -263,11 +263,36 @@
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 @@
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 @@
}
tools := r.Tools()
- commands := r.Commands()
+ commands := r.NinjaEscapedCommands()
outputs := r.Outputs()
if len(commands) == 0 {
@@ -334,7 +359,7 @@
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 @@
}
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 @@
}
// 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 @@
// 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
@@ -439,6 +478,16 @@
return c.Text(flag)
}
+// OptionalFlag adds the specified raw text to the command line if it is not nil. The text should not contain input or
+// output paths or the rule will not have them listed in its dependencies or outputs.
+func (c *RuleBuilderCommand) OptionalFlag(flag *string) *RuleBuilderCommand {
+ if flag != nil {
+ c.Text(*flag)
+ }
+
+ return c
+}
+
// Flags adds the specified raw text to the command line. The text should not contain input or output paths or the
// rule will not have them listed in its dependencies or outputs.
func (c *RuleBuilderCommand) Flags(flags []string) *RuleBuilderCommand {
@@ -478,6 +527,24 @@
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 +673,56 @@
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 cfbc2ab..6eba4f1 100644
--- a/android/rule_builder_test.go
+++ b/android/rule_builder_test.go
@@ -38,6 +38,7 @@
"ls": nil,
"turbine": nil,
"java": nil,
+ "javac": nil,
})
}
@@ -235,6 +236,34 @@
// 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 @@
"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/apex/apex.go b/apex/apex.go
index 2a2fabc..8b0f385 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -449,6 +449,7 @@
ctx.AddFarVariationDependencies([]blueprint.Variation{
{Mutator: "arch", Variation: arch},
{Mutator: "image", Variation: imageVariation},
+ {Mutator: "test_per_src", Variation: ""}, // "" is the all-tests variant
}, testTag, tests...)
}
@@ -492,6 +493,7 @@
ctx.AddFarVariationDependencies([]blueprint.Variation{
{Mutator: "arch", Variation: target.String()},
{Mutator: "image", Variation: a.getImageVariation(config)},
+ {Mutator: "test_per_src", Variation: ""}, // "" is the all-tests variant
}, testTag, a.properties.Tests...)
// Add native modules targetting both ABIs
@@ -692,6 +694,12 @@
return
}
+func getCopyManifestForTestPerSrcExecutables(cc *cc.Module) (filesToCopy []android.Path, dirInApex string) {
+ dirInApex = filepath.Join("bin", cc.RelativeInstallPath())
+ filesToCopy = cc.TestPerSrcOutputFiles()
+ return
+}
+
func getCopyManifestForPyBinary(py *python.Module) (fileToCopy android.Path, dirInApex string) {
dirInApex = "bin"
fileToCopy = py.HostToolPath().Path()
@@ -827,8 +835,22 @@
}
case testTag:
if cc, ok := child.(*cc.Module); ok {
- fileToCopy, dirInApex := getCopyManifestForExecutable(cc)
- filesInfo = append(filesInfo, apexFile{fileToCopy, depName, dirInApex, nativeTest, cc, nil})
+ if cc.TestPerSrcOutputFiles() != nil {
+ // Multiple-output test module (using `test_per_src`).
+ filesToCopy, dirInApex := getCopyManifestForTestPerSrcExecutables(cc)
+ for _, fileToCopy := range filesToCopy {
+ // Handle modules created as `test_per_src` variations of a single test module:
+ // replace the name of the original test module (`depName`, shared by all
+ // `test_per_src` variants of that module) with the name of the generated test
+ // binary.
+ moduleName := filepath.Base(fileToCopy.String())
+ filesInfo = append(filesInfo, apexFile{fileToCopy, moduleName, dirInApex, nativeTest, cc, nil})
+ }
+ } else {
+ // Single-output test module (not using `test_per_src`).
+ fileToCopy, dirInApex := getCopyManifestForExecutable(cc)
+ filesInfo = append(filesInfo, apexFile{fileToCopy, depName, dirInApex, nativeTest, cc, nil})
+ }
return true
} else {
ctx.PropertyErrorf("tests", "%q is not a cc module", depName)
@@ -1009,7 +1031,7 @@
if f.installDir == "bin" || strings.HasPrefix(f.installDir, "bin/") {
executablePaths = append(executablePaths, pathInApex)
for _, s := range f.symlinks {
- executablePaths = append(executablePaths, filepath.Join("bin", s))
+ executablePaths = append(executablePaths, filepath.Join(f.installDir, s))
}
} else {
readOnlyPaths = append(readOnlyPaths, pathInApex)
@@ -1430,6 +1452,13 @@
// Optional name for the installed apex. If unspecified, name of the
// module is used as the file name
Filename *string
+
+ // Names of modules to be overridden. Listed modules can only be other binaries
+ // (in Make or Soong).
+ // This does not completely prevent installation of the overridden binaries, but if both
+ // binaries would be installed by default (in PRODUCT_PACKAGES) the other binary will be removed
+ // from PRODUCT_PACKAGES.
+ Overrides []string
}
func (p *Prebuilt) installable() bool {
@@ -1443,7 +1472,7 @@
// Force disable the prebuilts when we are doing unbundled build. We do unbundled build
// to build the prebuilts themselves.
- forceDisable = forceDisable || !ctx.Config().UnbundledBuild()
+ forceDisable = forceDisable || ctx.Config().UnbundledBuild()
// b/137216042 don't use prebuilts when address sanitizer is on
forceDisable = forceDisable || android.InList("address", ctx.Config().SanitizeDevice()) ||
@@ -1525,17 +1554,16 @@
return p.prebuilt.Name(p.ModuleBase.Name())
}
-func (p *Prebuilt) AndroidMk() android.AndroidMkData {
- return android.AndroidMkData{
+func (p *Prebuilt) AndroidMkEntries() android.AndroidMkEntries {
+ return android.AndroidMkEntries{
Class: "ETC",
OutputFile: android.OptionalPathForPath(p.inputApex),
Include: "$(BUILD_PREBUILT)",
- Extra: []android.AndroidMkExtraFunc{
- func(w io.Writer, outputFile android.Path) {
- fmt.Fprintln(w, "LOCAL_MODULE_PATH :=", filepath.Join("$(OUT_DIR)", p.installDir.RelPathString()))
- fmt.Fprintln(w, "LOCAL_MODULE_STEM :=", p.installFilename)
- fmt.Fprintln(w, "LOCAL_UNINSTALLABLE_MODULE :=", !p.installable())
- },
+ AddCustomEntries: func(name, prefix, moduleDir string, entries *android.AndroidMkEntries) {
+ entries.SetString("LOCAL_MODULE_PATH", filepath.Join("$(OUT_DIR)", p.installDir.RelPathString()))
+ entries.SetString("LOCAL_MODULE_STEM", p.installFilename)
+ entries.SetBoolIfTrue("LOCAL_UNINSTALLABLE_MODULE", !p.installable())
+ entries.AddStrings("LOCAL_OVERRIDES_PACKAGES", p.properties.Overrides...)
},
}
}
diff --git a/apex/apex_test.go b/apex/apex_test.go
index 94cf19d..bb0c4c5 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -17,6 +17,7 @@
import (
"io/ioutil"
"os"
+ "reflect"
"strings"
"testing"
@@ -45,13 +46,13 @@
t.Fatalf("missing expected error %q (0 errors are returned)", pattern)
}
-func testApex(t *testing.T, bp string) *android.TestContext {
+func testApex(t *testing.T, bp string) (*android.TestContext, android.Config) {
ctx, config := testApexContext(t, bp)
_, errs := ctx.ParseFileList(".", []string{"Android.bp"})
android.FailIfErrored(t, errs)
_, errs = ctx.PrepareBuildActions(config)
android.FailIfErrored(t, errs)
- return ctx
+ return ctx, config
}
func testApexContext(t *testing.T, bp string) (*android.TestContext, android.Config) {
@@ -97,6 +98,7 @@
ctx.BottomUp("image", cc.ImageMutator).Parallel()
ctx.BottomUp("link", cc.LinkageMutator).Parallel()
ctx.BottomUp("vndk", cc.VndkMutator).Parallel()
+ ctx.BottomUp("test_per_src", cc.TestPerSrcMutator).Parallel()
ctx.BottomUp("version", cc.VersionMutator).Parallel()
ctx.BottomUp("begin", cc.BeginMutator).Parallel()
})
@@ -196,8 +198,11 @@
"system/sepolicy/apex/otherapex-file_contexts": nil,
"system/sepolicy/apex/commonapex-file_contexts": nil,
"mylib.cpp": nil,
- "mytest.cpp": nil,
"mylib_common.cpp": nil,
+ "mytest.cpp": nil,
+ "mytest1.cpp": nil,
+ "mytest2.cpp": nil,
+ "mytest3.cpp": nil,
"myprebuilt": nil,
"my_include": nil,
"vendor/foo/devkeys/test.x509.pem": nil,
@@ -264,7 +269,7 @@
// Minimal test
func TestBasicApex(t *testing.T) {
- ctx := testApex(t, `
+ ctx, _ := testApex(t, `
apex_defaults {
name: "myapex-defaults",
manifest: ":myapex.manifest",
@@ -388,7 +393,7 @@
}
func TestBasicZipApex(t *testing.T) {
- ctx := testApex(t, `
+ ctx, _ := testApex(t, `
apex {
name: "myapex",
key: "myapex.key",
@@ -436,7 +441,7 @@
}
func TestApexWithStubs(t *testing.T) {
- ctx := testApex(t, `
+ ctx, _ := testApex(t, `
apex {
name: "myapex",
key: "myapex.key",
@@ -520,7 +525,7 @@
}
func TestApexWithExplicitStubsDependency(t *testing.T) {
- ctx := testApex(t, `
+ ctx, _ := testApex(t, `
apex {
name: "myapex",
key: "myapex.key",
@@ -587,7 +592,7 @@
}
func TestApexWithSystemLibsStubs(t *testing.T) {
- ctx := testApex(t, `
+ ctx, _ := testApex(t, `
apex {
name: "myapex",
key: "myapex.key",
@@ -708,7 +713,7 @@
}
func TestFilesInSubDir(t *testing.T) {
- ctx := testApex(t, `
+ ctx, _ := testApex(t, `
apex {
name: "myapex",
key: "myapex.key",
@@ -768,7 +773,7 @@
}
func TestUseVendor(t *testing.T) {
- ctx := testApex(t, `
+ ctx, _ := testApex(t, `
apex {
name: "myapex",
key: "myapex.key",
@@ -842,7 +847,7 @@
}
func TestStaticLinking(t *testing.T) {
- ctx := testApex(t, `
+ ctx, _ := testApex(t, `
apex {
name: "myapex",
key: "myapex.key",
@@ -882,7 +887,7 @@
}
func TestKeys(t *testing.T) {
- ctx := testApex(t, `
+ ctx, _ := testApex(t, `
apex {
name: "myapex_keytest",
key: "myapex.key",
@@ -936,7 +941,7 @@
}
func TestMacro(t *testing.T) {
- ctx := testApex(t, `
+ ctx, _ := testApex(t, `
apex {
name: "myapex",
key: "myapex.key",
@@ -980,7 +985,7 @@
}
func TestHeaderLibsDependency(t *testing.T) {
- ctx := testApex(t, `
+ ctx, _ := testApex(t, `
apex {
name: "myapex",
key: "myapex.key",
@@ -1028,7 +1033,7 @@
}
func TestNonTestApex(t *testing.T) {
- ctx := testApex(t, `
+ ctx, _ := testApex(t, `
apex {
name: "myapex",
key: "myapex.key",
@@ -1079,7 +1084,7 @@
if android.InAnyApex("mylib_common_test") {
t.Fatal("mylib_common_test must not be used in any other tests since this checks that global state is not updated in an illegal way!")
}
- ctx := testApex(t, `
+ ctx, _ := testApex(t, `
apex_test {
name: "myapex",
key: "myapex.key",
@@ -1127,7 +1132,7 @@
}
func TestApexWithTarget(t *testing.T) {
- ctx := testApex(t, `
+ ctx, _ := testApex(t, `
apex {
name: "myapex",
key: "myapex.key",
@@ -1207,7 +1212,7 @@
}
func TestApexWithShBinary(t *testing.T) {
- ctx := testApex(t, `
+ ctx, _ := testApex(t, `
apex {
name: "myapex",
key: "myapex.key",
@@ -1235,7 +1240,7 @@
}
func TestApexInProductPartition(t *testing.T) {
- ctx := testApex(t, `
+ ctx, _ := testApex(t, `
apex {
name: "myapex",
key: "myapex.key",
@@ -1267,7 +1272,7 @@
}
func TestApexKeyFromOtherModule(t *testing.T) {
- ctx := testApex(t, `
+ ctx, _ := testApex(t, `
apex_key {
name: "myapex.key",
public_key: ":my.avbpubkey",
@@ -1300,7 +1305,7 @@
}
func TestPrebuilt(t *testing.T) {
- ctx := testApex(t, `
+ ctx, _ := testApex(t, `
prebuilt_apex {
name: "myapex",
arch: {
@@ -1323,7 +1328,7 @@
}
func TestPrebuiltFilenameOverride(t *testing.T) {
- ctx := testApex(t, `
+ ctx, _ := testApex(t, `
prebuilt_apex {
name: "myapex",
src: "myapex-arm.apex",
@@ -1339,13 +1344,34 @@
}
}
+func TestPrebuiltOverrides(t *testing.T) {
+ ctx, config := testApex(t, `
+ prebuilt_apex {
+ name: "myapex.prebuilt",
+ src: "myapex-arm.apex",
+ overrides: [
+ "myapex",
+ ],
+ }
+ `)
+
+ p := ctx.ModuleForTests("myapex.prebuilt", "android_common").Module().(*Prebuilt)
+
+ expected := []string{"myapex"}
+ actual := android.AndroidMkEntriesForTest(t, config, "", p).EntryMap["LOCAL_OVERRIDES_PACKAGES"]
+ if !reflect.DeepEqual(actual, expected) {
+ t.Errorf("Incorrect LOCAL_OVERRIDES_PACKAGES value '%s', expected '%s'", actual, expected)
+ }
+}
+
func TestApexWithTests(t *testing.T) {
- ctx := testApex(t, `
+ ctx, _ := testApex(t, `
apex_test {
name: "myapex",
key: "myapex.key",
tests: [
"mytest",
+ "mytests",
],
}
@@ -1364,6 +1390,21 @@
static_executable: true,
stl: "none",
}
+
+ cc_test {
+ name: "mytests",
+ gtest: false,
+ srcs: [
+ "mytest1.cpp",
+ "mytest2.cpp",
+ "mytest3.cpp",
+ ],
+ test_per_src: true,
+ relative_install_path: "test",
+ system_shared_libs: [],
+ static_executable: true,
+ stl: "none",
+ }
`)
apexRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexRule")
@@ -1371,10 +1412,15 @@
// Ensure that test dep is copied into apex.
ensureContains(t, copyCmds, "image.apex/bin/test/mytest")
+
+ // Ensure that test deps built with `test_per_src` are copied into apex.
+ ensureContains(t, copyCmds, "image.apex/bin/test/mytest1")
+ ensureContains(t, copyCmds, "image.apex/bin/test/mytest2")
+ ensureContains(t, copyCmds, "image.apex/bin/test/mytest3")
}
func TestApexUsesOtherApex(t *testing.T) {
- ctx := testApex(t, `
+ ctx, _ := testApex(t, `
apex {
name: "myapex",
key: "myapex.key",
diff --git a/cc/builder.go b/cc/builder.go
index ee40736..cbe2c88 100644
--- a/cc/builder.go
+++ b/cc/builder.go
@@ -78,7 +78,7 @@
blueprint.RuleParams{
// Without -no-pie, clang 7.0 adds -pie to link Android files,
// but -r and -pie cannot be used together.
- Command: "$ldCmd -nostdlib -no-pie -Wl,-r ${in} -o ${out} ${ldFlags}",
+ Command: "$ldCmd -fuse-ld=lld -nostdlib -no-pie -Wl,-r ${in} -o ${out} ${ldFlags}",
CommandDeps: []string{"$ldCmd"},
},
"ldCmd", "ldFlags")
diff --git a/cc/cc.go b/cc/cc.go
index a0ab255..2cee807 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -40,7 +40,7 @@
ctx.BottomUp("link", LinkageMutator).Parallel()
ctx.BottomUp("vndk", VndkMutator).Parallel()
ctx.BottomUp("ndk_api", ndkApiMutator).Parallel()
- ctx.BottomUp("test_per_src", testPerSrcMutator).Parallel()
+ ctx.BottomUp("test_per_src", TestPerSrcMutator).Parallel()
ctx.BottomUp("version", VersionMutator).Parallel()
ctx.BottomUp("begin", BeginMutator).Parallel()
ctx.BottomUp("sysprop", SyspropMutator).Parallel()
@@ -179,6 +179,9 @@
}
type ObjectLinkerProperties struct {
+ // list of modules that should only provide headers for this module.
+ Header_libs []string `android:"arch_variant,variant_prepend"`
+
// names of other cc_object modules to link into this module using partial linking
Objs []string `android:"arch_variant"`
@@ -369,6 +372,7 @@
vndkExtDepTag = dependencyTag{name: "vndk extends", library: true}
runtimeDepTag = dependencyTag{name: "runtime lib"}
coverageDepTag = dependencyTag{name: "coverage"}
+ testPerSrcDepTag = dependencyTag{name: "test_per_src"}
)
// Module contains the properties and members used by all C/C++ module types, and implements
@@ -404,6 +408,9 @@
outputFile android.OptionalPath
+ // Test output files, in the case of a test module using `test_per_src`.
+ testPerSrcOutputFiles []android.Path
+
cachedToolchain config.Toolchain
subAndroidMkOnce map[subAndroidMkProvider]bool
@@ -426,6 +433,10 @@
return c.outputFile
}
+func (c *Module) TestPerSrcOutputFiles() []android.Path {
+ return c.testPerSrcOutputFiles
+}
+
func (c *Module) UnstrippedOutputFile() android.Path {
if c.linker != nil {
return c.linker.unstrippedOutputFilePath()
@@ -940,6 +951,29 @@
}
func (c *Module) GenerateAndroidBuildActions(actx android.ModuleContext) {
+ // Handle the case of a test module split by `test_per_src` mutator.
+ if test, ok := c.linker.(testPerSrc); ok {
+ // The `test_per_src` mutator adds an extra variant named "", depending on all the
+ // other `test_per_src` variants of the test module. Collect the output files of
+ // these dependencies and record them in the `testPerSrcOutputFiles` for later use
+ // (see e.g. `apexBundle.GenerateAndroidBuildActions`).
+ if test.isAllTestsVariation() {
+ var testPerSrcOutputFiles []android.Path
+ for _, dep := range actx.GetDirectDepsWithTag(testPerSrcDepTag) {
+ if ccDep, ok := dep.(*Module); ok {
+ depOutputFile := ccDep.OutputFile().Path()
+ testPerSrcOutputFiles =
+ append(testPerSrcOutputFiles, depOutputFile)
+ }
+ }
+ c.testPerSrcOutputFiles = testPerSrcOutputFiles
+ // Set outputFile to an empty path, as this module does not produce an
+ // output file per se.
+ c.outputFile = android.OptionalPath{}
+ return
+ }
+ }
+
c.makeLinkType = c.getMakeLinkType(actx)
ctx := &moduleContext{
@@ -2083,6 +2117,7 @@
&VendorProperties{},
&BaseCompilerProperties{},
&BaseLinkerProperties{},
+ &ObjectLinkerProperties{},
&LibraryProperties{},
&FlagExporterProperties{},
&BinaryLinkerProperties{},
diff --git a/cc/cc_test.go b/cc/cc_test.go
index ca34185..c619b5a 100644
--- a/cc/cc_test.go
+++ b/cc/cc_test.go
@@ -2264,6 +2264,22 @@
}
}
+// Simple smoke test for the cc_fuzz target that ensures the rule compiles
+// correctly.
+func TestFuzzTarget(t *testing.T) {
+ ctx := testCc(t, `
+ cc_fuzz {
+ name: "fuzz_smoke_test",
+ srcs: ["foo.c"],
+ }`)
+
+ variant := "android_arm64_armv8-a_core"
+ ctx.ModuleForTests("fuzz_smoke_test", variant).Rule("cc")
+}
+
+func TestAidl(t *testing.T) {
+}
+
func assertString(t *testing.T, got, expected string) {
t.Helper()
if got != expected {
diff --git a/cc/compiler.go b/cc/compiler.go
index fd6184b..0f9599e 100644
--- a/cc/compiler.go
+++ b/cc/compiler.go
@@ -485,7 +485,7 @@
"-I"+android.PathForModuleGen(ctx, "aidl").String())
}
- if compiler.hasSrcExt(".rs") || compiler.hasSrcExt(".fs") {
+ if compiler.hasSrcExt(".rscript") || compiler.hasSrcExt(".fs") {
flags = rsFlags(ctx, flags, &compiler.Properties)
}
diff --git a/cc/config/toolchain.go b/cc/config/toolchain.go
index d5e9d01..db9092d 100644
--- a/cc/config/toolchain.go
+++ b/cc/config/toolchain.go
@@ -181,6 +181,9 @@
if arch == "" {
return ""
}
+ if !t.Bionic() {
+ return "libclang_rt." + library + "-" + arch
+ }
return "libclang_rt." + library + "-" + arch + "-android"
}
@@ -224,6 +227,10 @@
return LibclangRuntimeLibrary(t, "scudo_minimal")
}
+func LibFuzzerRuntimeLibrary(t Toolchain) string {
+ return LibclangRuntimeLibrary(t, "fuzzer")
+}
+
func ToolPath(t Toolchain) string {
if p := t.ToolPath(); p != "" {
return p
diff --git a/cc/config/x86_linux_host.go b/cc/config/x86_linux_host.go
index f072f34..f08a379 100644
--- a/cc/config/x86_linux_host.go
+++ b/cc/config/x86_linux_host.go
@@ -233,6 +233,14 @@
return "${config.LinuxX8664YasmFlags}"
}
+func (toolchainLinuxX86) LibclangRuntimeLibraryArch() string {
+ return "i686"
+}
+
+func (toolchainLinuxX8664) LibclangRuntimeLibraryArch() string {
+ return "x86_64"
+}
+
func (t *toolchainLinux) AvailableLibraries() []string {
return linuxAvailableLibraries
}
diff --git a/cc/fuzz.go b/cc/fuzz.go
new file mode 100644
index 0000000..3b0c5c8
--- /dev/null
+++ b/cc/fuzz.go
@@ -0,0 +1,120 @@
+// Copyright 2016 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package cc
+
+import (
+ "android/soong/android"
+ "android/soong/cc/config"
+)
+
+func init() {
+ android.RegisterModuleType("cc_fuzz", FuzzFactory)
+}
+
+// cc_fuzz creates a host/device fuzzer binary. Host binaries can be found at
+// $ANDROID_HOST_OUT/fuzz/, and device binaries can be found at /data/fuzz on
+// your device, or $ANDROID_PRODUCT_OUT/data/fuzz in your build tree.
+func FuzzFactory() android.Module {
+ module := NewFuzz(android.HostAndDeviceSupported)
+ return module.Init()
+}
+
+func NewFuzzInstaller() *baseInstaller {
+ return NewBaseInstaller("fuzz", "fuzz", InstallInData)
+}
+
+type fuzzBinary struct {
+ *binaryDecorator
+ *baseCompiler
+}
+
+func (fuzz *fuzzBinary) linkerProps() []interface{} {
+ props := fuzz.binaryDecorator.linkerProps()
+ return props
+}
+
+func (fuzz *fuzzBinary) linkerInit(ctx BaseModuleContext) {
+ // Add ../lib[64] to rpath so that out/host/linux-x86/fuzz/<fuzzer> can
+ // find out/host/linux-x86/lib[64]/library.so
+ runpaths := []string{"../lib"}
+ for _, runpath := range runpaths {
+ if ctx.toolchain().Is64Bit() {
+ runpath += "64"
+ }
+ fuzz.binaryDecorator.baseLinker.dynamicProperties.RunPaths = append(
+ fuzz.binaryDecorator.baseLinker.dynamicProperties.RunPaths, runpath)
+ }
+
+ // add "" to rpath so that fuzzer binaries can find libraries in their own fuzz directory
+ fuzz.binaryDecorator.baseLinker.dynamicProperties.RunPaths = append(
+ fuzz.binaryDecorator.baseLinker.dynamicProperties.RunPaths, "")
+
+ fuzz.binaryDecorator.linkerInit(ctx)
+}
+
+func (fuzz *fuzzBinary) linkerDeps(ctx DepsContext, deps Deps) Deps {
+ deps.StaticLibs = append(deps.StaticLibs,
+ config.LibFuzzerRuntimeLibrary(ctx.toolchain()))
+ deps = fuzz.binaryDecorator.linkerDeps(ctx, deps)
+ return deps
+}
+
+func (fuzz *fuzzBinary) linkerFlags(ctx ModuleContext, flags Flags) Flags {
+ flags = fuzz.binaryDecorator.linkerFlags(ctx, flags)
+ return flags
+}
+
+func (fuzz *fuzzBinary) install(ctx ModuleContext, file android.Path) {
+ fuzz.binaryDecorator.baseInstaller.dir = "fuzz"
+ fuzz.binaryDecorator.baseInstaller.dir64 = "fuzz"
+ fuzz.binaryDecorator.baseInstaller.install(ctx, file)
+}
+
+func NewFuzz(hod android.HostOrDeviceSupported) *Module {
+ module, binary := NewBinary(hod)
+
+ // TODO(mitchp): The toolchain does not currently export the x86 (32-bit)
+ // variant of libFuzzer for host. There is no way to only disable the host
+ // 32-bit variant, so we specify cc_fuzz targets as 64-bit only. This doesn't
+ // hurt anyone, as cc_fuzz is mostly for experimental targets as of this
+ // moment.
+ module.multilib = "64"
+
+ binary.baseInstaller = NewFuzzInstaller()
+ module.sanitize.SetSanitizer(fuzzer, true)
+
+ fuzz := &fuzzBinary{
+ binaryDecorator: binary,
+ baseCompiler: NewBaseCompiler(),
+ }
+ module.compiler = fuzz
+ module.linker = fuzz
+ module.installer = fuzz
+
+ // The fuzzer runtime is not present for darwin host modules, disable cc_fuzz modules when targeting darwin.
+ android.AddLoadHook(module, func(ctx android.LoadHookContext) {
+ disableDarwin := struct {
+ Target struct {
+ Darwin struct {
+ Enabled *bool
+ }
+ }
+ }{}
+ disableDarwin.Target.Darwin.Enabled = BoolPtr(false)
+ ctx.AppendProperties(&disableDarwin)
+ })
+
+ return module
+}
diff --git a/cc/gen.go b/cc/gen.go
index 7516b28..42b0cbe 100644
--- a/cc/gen.go
+++ b/cc/gen.go
@@ -99,7 +99,7 @@
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).
@@ -120,8 +120,13 @@
headerBn := outDir.Join(ctx, aidlPackage, "Bn"+shortName+".h")
headerBp := outDir.Join(ctx, aidlPackage, "Bp"+shortName+".h")
+ baseDir := strings.TrimSuffix(aidlFile.String(), aidlFile.Rel())
+ if baseDir != "" {
+ aidlFlags += " -I" + baseDir
+ }
+
cmd := rule.Command()
- cmd.Tool(ctx.Config().HostToolPath(ctx, "aidl-cpp")).
+ cmd.BuiltTool(ctx, "aidl-cpp").
FlagWithDepFile("-d", depFile).
Flag("--ninja").
Flag(aidlFlags).
@@ -238,7 +243,7 @@
depFile := android.GenPathWithExt(ctx, "aidl", srcFile, "cpp.d")
srcFiles[i] = cppFile
deps = append(deps, genAidl(ctx, aidlRule, srcFile, cppFile, depFile, buildFlags.aidlFlags)...)
- case ".rs", ".fs":
+ case ".rscript", ".fs":
cppFile := rsGeneratedCppFile(ctx, srcFile)
rsFiles = append(rsFiles, srcFiles[i])
srcFiles[i] = cppFile
diff --git a/cc/gen_test.go b/cc/gen_test.go
index e4219d9..da3b4e8 100644
--- a/cc/gen_test.go
+++ b/cc/gen_test.go
@@ -16,6 +16,7 @@
import (
"path/filepath"
+ "strings"
"testing"
)
@@ -42,7 +43,8 @@
ctx := testCc(t, `
filegroup {
name: "fg",
- srcs: ["b.aidl"],
+ srcs: ["sub/c.aidl"],
+ path: "sub",
}
cc_library_shared {
@@ -59,6 +61,12 @@
if !inList("-I"+filepath.Dir(aidl.Output.String()), libfoo.flags.GlobalFlags) {
t.Errorf("missing aidl includes in global flags")
}
+
+ aidlCommand := aidl.RuleParams.Command
+ if !strings.Contains(aidlCommand, "-Isub") {
+ t.Errorf("aidl command for c.aidl should contain \"-Isub\", but was %q", aidlCommand)
+ }
+
})
}
diff --git a/cc/linker.go b/cc/linker.go
index dda2fcb..fa3b0a6 100644
--- a/cc/linker.go
+++ b/cc/linker.go
@@ -483,7 +483,7 @@
Input: in,
Output: out,
Args: map[string]string{
- "buildNumberFromFile": ctx.Config().BuildNumberFromFile(),
+ "buildNumberFromFile": proptools.NinjaEscape(ctx.Config().BuildNumberFromFile()),
},
})
}
diff --git a/cc/makevars.go b/cc/makevars.go
index 78a32c8..2b49772 100644
--- a/cc/makevars.go
+++ b/cc/makevars.go
@@ -138,7 +138,6 @@
ctx.Strict("ADDRESS_SANITIZER_CONFIG_EXTRA_CFLAGS", strings.Join(asanCflags, " "))
ctx.Strict("ADDRESS_SANITIZER_CONFIG_EXTRA_LDFLAGS", strings.Join(asanLdflags, " "))
- ctx.Strict("ADDRESS_SANITIZER_CONFIG_EXTRA_STATIC_LIBRARIES", strings.Join(asanLibs, " "))
ctx.Strict("HWADDRESS_SANITIZER_CONFIG_EXTRA_CFLAGS", strings.Join(hwasanCflags, " "))
ctx.Strict("HWADDRESS_SANITIZER_GLOBAL_OPTIONS", strings.Join(hwasanGlobalOptions, ","))
diff --git a/cc/object.go b/cc/object.go
index 50ecc38..9fa0ac9 100644
--- a/cc/object.go
+++ b/cc/object.go
@@ -66,6 +66,7 @@
deps.LateSharedLibs = append(deps.LateSharedLibs, "libc")
}
+ deps.HeaderLibs = append(deps.HeaderLibs, object.Properties.Header_libs...)
deps.ObjFiles = append(deps.ObjFiles, object.Properties.Objs...)
return deps
}
diff --git a/cc/rs.go b/cc/rs.go
index fbc6bfb..5951edb 100644
--- a/cc/rs.go
+++ b/cc/rs.go
@@ -51,7 +51,7 @@
"depFiles", "outDir", "rsFlags", "stampFile")
)
-// Takes a path to a .rs or .fs file, and returns a path to a generated ScriptC_*.cpp file
+// Takes a path to a .rscript or .fs file, and returns a path to a generated ScriptC_*.cpp file
// This has to match the logic in llvm-rs-cc in DetermineOutputFile.
func rsGeneratedCppFile(ctx android.ModuleContext, rsFile android.Path) android.WritablePath {
fileName := strings.TrimSuffix(rsFile.Base(), rsFile.Ext())
diff --git a/cc/sanitize.go b/cc/sanitize.go
index c59f53a..b238b7e 100644
--- a/cc/sanitize.go
+++ b/cc/sanitize.go
@@ -33,7 +33,6 @@
asanCflags = []string{"-fno-omit-frame-pointer"}
asanLdflags = []string{"-Wl,-u,__asan_preinit"}
- asanLibs = []string{"libasan"}
// TODO(pcc): Stop passing -hwasan-allow-ifunc here once it has been made
// the default.
@@ -391,7 +390,6 @@
if ctx.Device() {
if Bool(sanitize.Properties.Sanitize.Address) {
- deps.StaticLibs = append(deps.StaticLibs, asanLibs...)
// Compiling asan and having libc_scudo in the same
// executable will cause the executable to crash.
// Remove libc_scudo since it is only used to override
diff --git a/cc/test.go b/cc/test.go
index c735fd9..aff8ba5 100644
--- a/cc/test.go
+++ b/cc/test.go
@@ -121,7 +121,9 @@
type testPerSrc interface {
testPerSrc() bool
srcs() []string
+ isAllTestsVariation() bool
setSrc(string, string)
+ unsetSrc()
}
func (test *testBinary) testPerSrc() bool {
@@ -132,28 +134,55 @@
return test.baseCompiler.Properties.Srcs
}
+func (test *testBinary) isAllTestsVariation() bool {
+ stem := test.binaryDecorator.Properties.Stem
+ return stem != nil && *stem == ""
+}
+
func (test *testBinary) setSrc(name, src string) {
test.baseCompiler.Properties.Srcs = []string{src}
test.binaryDecorator.Properties.Stem = StringPtr(name)
}
+func (test *testBinary) unsetSrc() {
+ test.baseCompiler.Properties.Srcs = nil
+ test.binaryDecorator.Properties.Stem = StringPtr("")
+}
+
var _ testPerSrc = (*testBinary)(nil)
-func testPerSrcMutator(mctx android.BottomUpMutatorContext) {
+func TestPerSrcMutator(mctx android.BottomUpMutatorContext) {
if m, ok := mctx.Module().(*Module); ok {
if test, ok := m.linker.(testPerSrc); ok {
- if test.testPerSrc() && len(test.srcs()) > 0 {
+ numTests := len(test.srcs())
+ if test.testPerSrc() && numTests > 0 {
if duplicate, found := checkDuplicate(test.srcs()); found {
mctx.PropertyErrorf("srcs", "found a duplicate entry %q", duplicate)
return
}
- testNames := make([]string, len(test.srcs()))
+ testNames := make([]string, numTests)
for i, src := range test.srcs() {
testNames[i] = strings.TrimSuffix(filepath.Base(src), filepath.Ext(src))
}
+ // In addition to creating one variation per test source file,
+ // create an additional "all tests" variation named "", and have it
+ // depends on all other test_per_src variations. This is useful to
+ // create subsequent dependencies of a given module on all
+ // test_per_src variations created above: by depending on
+ // variation "", that module will transitively depend on all the
+ // other test_per_src variations without the need to know their
+ // name or even their number.
+ testNames = append(testNames, "")
tests := mctx.CreateLocalVariations(testNames...)
+ all_tests := tests[numTests]
+ all_tests.(*Module).linker.(testPerSrc).unsetSrc()
+ // Prevent the "all tests" variation from being installable nor
+ // exporting to Make, as it won't create any output file.
+ all_tests.(*Module).Properties.PreventInstall = true
+ all_tests.(*Module).Properties.HideFromMake = true
for i, src := range test.srcs() {
tests[i].(*Module).linker.(testPerSrc).setSrc(testNames[i], src)
+ mctx.AddInterVariantDependency(testPerSrcDepTag, all_tests, tests[i])
}
}
}
@@ -210,6 +239,11 @@
deps.StaticLibs = append(deps.StaticLibs, "libgtest_main_ndk_c++", "libgtest_ndk_c++")
} else if BoolDefault(test.Properties.Isolated, false) {
deps.StaticLibs = append(deps.StaticLibs, "libgtest_isolated_main")
+ // The isolated library requires liblog, but adding it
+ // as a static library means unit tests cannot override
+ // liblog functions. Instead make it a shared library
+ // dependency.
+ deps.SharedLibs = append(deps.SharedLibs, "liblog")
} else {
deps.StaticLibs = append(deps.StaticLibs, "libgtest_main", "libgtest")
}
diff --git a/cc/testing.go b/cc/testing.go
index df7cb78..f0ad33b 100644
--- a/cc/testing.go
+++ b/cc/testing.go
@@ -63,6 +63,41 @@
}
toolchain_library {
+ name: "libclang_rt.fuzzer-arm-android",
+ vendor_available: true,
+ recovery_available: true,
+ src: "",
+ }
+
+ toolchain_library {
+ name: "libclang_rt.fuzzer-aarch64-android",
+ vendor_available: true,
+ recovery_available: true,
+ src: "",
+ }
+
+ toolchain_library {
+ name: "libclang_rt.fuzzer-i686-android",
+ vendor_available: true,
+ recovery_available: true,
+ src: "",
+ }
+
+ toolchain_library {
+ name: "libclang_rt.fuzzer-x86_64-android",
+ vendor_available: true,
+ recovery_available: true,
+ src: "",
+ }
+
+ toolchain_library {
+ name: "libclang_rt.fuzzer-x86_64",
+ vendor_available: true,
+ recovery_available: true,
+ src: "",
+ }
+
+ toolchain_library {
name: "libgcc",
vendor_available: true,
recovery_available: true,
@@ -196,6 +231,7 @@
ctx := android.NewTestArchContext()
ctx.RegisterModuleType("cc_binary", android.ModuleFactoryAdaptor(BinaryFactory))
ctx.RegisterModuleType("cc_binary_host", android.ModuleFactoryAdaptor(binaryHostFactory))
+ ctx.RegisterModuleType("cc_fuzz", android.ModuleFactoryAdaptor(FuzzFactory))
ctx.RegisterModuleType("cc_library", android.ModuleFactoryAdaptor(LibraryFactory))
ctx.RegisterModuleType("cc_library_shared", android.ModuleFactoryAdaptor(LibrarySharedFactory))
ctx.RegisterModuleType("cc_library_static", android.ModuleFactoryAdaptor(LibraryStaticFactory))
@@ -229,6 +265,7 @@
"bar.c": nil,
"a.proto": nil,
"b.aidl": nil,
+ "sub/c.aidl": nil,
"my_include": nil,
"foo.map.txt": nil,
"liba.so": nil,
diff --git a/cmd/pom2bp/pom2bp.go b/cmd/pom2bp/pom2bp.go
index c858c40..191b919 100644
--- a/cmd/pom2bp/pom2bp.go
+++ b/cmd/pom2bp/pom2bp.go
@@ -124,6 +124,25 @@
var hostModuleNames = HostModuleNames{}
+type HostAndDeviceModuleNames map[string]bool
+
+func (n HostAndDeviceModuleNames) IsHostAndDeviceModule(groupId string, artifactId string) bool {
+ _, found := n[groupId+":"+artifactId]
+
+ return found
+}
+
+func (n HostAndDeviceModuleNames) String() string {
+ return ""
+}
+
+func (n HostAndDeviceModuleNames) Set(v string) error {
+ n[v] = true
+ return nil
+}
+
+var hostAndDeviceModuleNames = HostAndDeviceModuleNames{}
+
var sdkVersion string
var useVersion string
var staticDeps bool
@@ -190,10 +209,14 @@
return !p.IsHostModule()
}
+func (p Pom) IsHostAndDeviceModule() bool {
+ return hostAndDeviceModuleNames.IsHostAndDeviceModule(p.GroupId, p.ArtifactId)
+}
+
func (p Pom) ModuleType() string {
if p.IsAar() {
return "android_library"
- } else if p.IsHostModule() {
+ } else if p.IsHostModule() && !p.IsHostAndDeviceModule() {
return "java_library_host"
} else {
return "java_library_static"
@@ -203,7 +226,7 @@
func (p Pom) ImportModuleType() string {
if p.IsAar() {
return "android_library_import"
- } else if p.IsHostModule() {
+ } else if p.IsHostModule() && !p.IsHostAndDeviceModule() {
return "java_import_host"
} else {
return "java_import"
@@ -340,6 +363,9 @@
{{- if .Jetifier}}
jetifier: true,
{{- end}}
+ {{- if .IsHostAndDeviceModule}}
+ host_supported: true,
+ {{- end}}
{{- if .IsAar}}
min_sdk_version: "{{.MinSdkVersion}}",
static_libs: [
@@ -372,6 +398,9 @@
{{- if .Jetifier}}
jetifier: true,
{{- end}}
+ {{- if .IsHostAndDeviceModule}}
+ host_supported: true,
+ {{- end}}
{{- if .IsAar}}
min_sdk_version: "{{.MinSdkVersion}}",
static_libs: [
@@ -399,6 +428,9 @@
name: "{{.BpName}}",
{{- if .IsDeviceModule}}
sdk_version: "{{.SdkVersion}}",
+ {{- if .IsHostAndDeviceModule}}
+ host_supported: true,
+ {{- end}}
{{- if .IsAar}}
min_sdk_version: "{{.MinSdkVersion}}",
manifest: "manifests/{{.BpName}}/AndroidManifest.xml",
@@ -564,6 +596,7 @@
flag.Var(&extraLibs, "extra-libs", "Extra runtime dependencies needed when depending on a module")
flag.Var(&rewriteNames, "rewrite", "Regex(es) to rewrite artifact names")
flag.Var(&hostModuleNames, "host", "Specifies that the corresponding module (specified in the form 'module.group:module.artifact') is a host module")
+ flag.Var(&hostAndDeviceModuleNames, "host-and-device", "Specifies that the corresponding module (specified in the form 'module.group:module.artifact') is both a host and device module.")
flag.StringVar(&sdkVersion, "sdk-version", "", "What to write to sdk_version")
flag.StringVar(&useVersion, "use-version", "", "Only read artifacts of a specific version")
flag.BoolVar(&staticDeps, "static-deps", false, "Statically include direct dependencies")
diff --git a/cmd/soong_ui/main.go b/cmd/soong_ui/main.go
index 4d59a39..0eaed76 100644
--- a/cmd/soong_ui/main.go
+++ b/cmd/soong_ui/main.go
@@ -342,15 +342,21 @@
action: build.BUILD_MODULES,
buildDependencies: true,
}, {
+ // buildDependencies is set to true as mm is being deprecated. This is redirecting to mma build
+ // command behaviour. Once it has soaked for a while, the build command is deleted from here once
+ // it has been removed from the envsetup.sh.
name: "modules-in-a-dir-no-deps",
description: "Build action: builds all of the modules in the current directory without their dependencies.",
action: build.BUILD_MODULES_IN_A_DIRECTORY,
- buildDependencies: false,
+ buildDependencies: true,
}, {
+ // buildDependencies is set to true as mmm is being deprecated. This is redirecting to mmma build
+ // command behaviour. Once it has soaked for a while, the build command is deleted from here once
+ // it has been removed from the envsetup.sh.
name: "modules-in-dirs-no-deps",
description: "Build action: builds all of the modules in the supplied directories without their dependencies.",
action: build.BUILD_MODULES_IN_DIRECTORIES,
- buildDependencies: false,
+ buildDependencies: true,
}, {
name: "modules-in-a-dir",
description: "Build action: builds all of the modules in the current directory and their dependencies.",
diff --git a/genrule/genrule.go b/genrule/genrule.go
index b0657ff..411da05 100644
--- a/genrule/genrule.go
+++ b/genrule/genrule.go
@@ -284,12 +284,12 @@
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 @@
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 @@
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 @@
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/androidmk_test.go b/java/androidmk_test.go
index 107837d..fbf2baa 100644
--- a/java/androidmk_test.go
+++ b/java/androidmk_test.go
@@ -15,18 +15,20 @@
package java
import (
- "android/soong/android"
"bytes"
"io"
"io/ioutil"
"strings"
"testing"
+
+ "android/soong/android"
)
type testAndroidMk struct {
*testing.T
body []byte
}
+
type testAndroidMkModule struct {
*testing.T
props map[string]string
@@ -115,30 +117,26 @@
}
func TestRequired(t *testing.T) {
- config := testConfig(nil)
- ctx := testContext(config, `
+ ctx, config := testJava(t, `
java_library {
name: "foo",
srcs: ["a.java"],
required: ["libfoo"],
}
- `, nil)
- run(t, ctx, config)
+ `)
mk := getAndroidMk(t, ctx, config, "foo")
mk.moduleFor("foo").hasRequired("libfoo")
}
func TestHostdex(t *testing.T) {
- config := testConfig(nil)
- ctx := testContext(config, `
+ ctx, config := testJava(t, `
java_library {
name: "foo",
srcs: ["a.java"],
hostdex: true,
}
- `, nil)
- run(t, ctx, config)
+ `)
mk := getAndroidMk(t, ctx, config, "foo")
mk.moduleFor("foo")
@@ -146,16 +144,14 @@
}
func TestHostdexRequired(t *testing.T) {
- config := testConfig(nil)
- ctx := testContext(config, `
+ ctx, config := testJava(t, `
java_library {
name: "foo",
srcs: ["a.java"],
hostdex: true,
required: ["libfoo"],
}
- `, nil)
- run(t, ctx, config)
+ `)
mk := getAndroidMk(t, ctx, config, "foo")
mk.moduleFor("foo").hasRequired("libfoo")
@@ -163,8 +159,7 @@
}
func TestHostdexSpecificRequired(t *testing.T) {
- config := testConfig(nil)
- ctx := testContext(config, `
+ ctx, config := testJava(t, `
java_library {
name: "foo",
srcs: ["a.java"],
@@ -175,8 +170,7 @@
},
},
}
- `, nil)
- run(t, ctx, config)
+ `)
mk := getAndroidMk(t, ctx, config, "foo")
mk.moduleFor("foo").hasNoRequired("libfoo")
diff --git a/java/app.go b/java/app.go
index 3442658..a679e88 100644
--- a/java/app.go
+++ b/java/app.go
@@ -816,7 +816,7 @@
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 @@
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 @@
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/app_test.go b/java/app_test.go
index f08969d..32de019 100644
--- a/java/app_test.go
+++ b/java/app_test.go
@@ -43,7 +43,7 @@
}
)
-func testAppContext(config android.Config, bp string, fs map[string][]byte) *android.TestContext {
+func testAppContext(bp string, fs map[string][]byte) *android.TestContext {
appFS := map[string][]byte{}
for k, v := range fs {
appFS[k] = v
@@ -53,13 +53,13 @@
appFS[file] = nil
}
- return testContext(config, bp, appFS)
+ return testContext(bp, appFS)
}
func testApp(t *testing.T, bp string) *android.TestContext {
config := testConfig(nil)
- ctx := testAppContext(config, bp, nil)
+ ctx := testAppContext(bp, nil)
run(t, ctx, config)
@@ -176,7 +176,7 @@
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
config := testConfig(nil)
- ctx := testContext(config, fmt.Sprintf(bp, testCase.prop), fs)
+ ctx := testContext(fmt.Sprintf(bp, testCase.prop), fs)
run(t, ctx, config)
module := ctx.ModuleForTests("foo", "android_common")
@@ -388,7 +388,7 @@
config.TestProductVariables.EnforceRROExcludedOverlays = testCase.enforceRROExcludedOverlays
}
- ctx := testAppContext(config, bp, fs)
+ ctx := testAppContext(bp, fs)
run(t, ctx, config)
resourceListToFiles := func(module android.TestingModule, list []string) (files []string) {
@@ -515,7 +515,7 @@
config.TestProductVariables.Platform_sdk_codename = &test.platformSdkCodename
config.TestProductVariables.Platform_sdk_final = &test.platformSdkFinal
- ctx := testAppContext(config, bp, nil)
+ ctx := testAppContext(bp, nil)
run(t, ctx, config)
@@ -547,7 +547,7 @@
}
func TestJNIABI(t *testing.T) {
- ctx := testJava(t, cc.GatherRequiredDepsForTest(android.Android)+`
+ ctx, _ := testJava(t, cc.GatherRequiredDepsForTest(android.Android)+`
cc_library {
name: "libjni",
system_shared_libs: [],
@@ -620,7 +620,7 @@
}
func TestJNIPackaging(t *testing.T) {
- ctx := testJava(t, cc.GatherRequiredDepsForTest(android.Android)+`
+ ctx, _ := testJava(t, cc.GatherRequiredDepsForTest(android.Android)+`
cc_library {
name: "libjni",
system_shared_libs: [],
@@ -774,7 +774,7 @@
if test.certificateOverride != "" {
config.TestProductVariables.CertificateOverrides = []string{test.certificateOverride}
}
- ctx := testAppContext(config, test.bp, nil)
+ ctx := testAppContext(test.bp, nil)
run(t, ctx, config)
foo := ctx.ModuleForTests("foo", "android_common")
@@ -832,7 +832,7 @@
if test.packageNameOverride != "" {
config.TestProductVariables.PackageNameOverrides = []string{test.packageNameOverride}
}
- ctx := testAppContext(config, test.bp, nil)
+ ctx := testAppContext(test.bp, nil)
run(t, ctx, config)
foo := ctx.ModuleForTests("foo", "android_common")
@@ -865,7 +865,7 @@
`
config := testConfig(nil)
config.TestProductVariables.ManifestPackageNameOverrides = []string{"foo:org.dandroid.bp"}
- ctx := testAppContext(config, bp, nil)
+ ctx := testAppContext(bp, nil)
run(t, ctx, config)
@@ -879,7 +879,7 @@
}
func TestOverrideAndroidApp(t *testing.T) {
- ctx := testJava(t, `
+ ctx, _ := testJava(t, `
android_app {
name: "foo",
srcs: ["a.java"],
@@ -980,7 +980,7 @@
}
func TestOverrideAndroidAppDependency(t *testing.T) {
- ctx := testJava(t, `
+ ctx, _ := testJava(t, `
android_app {
name: "foo",
srcs: ["a.java"],
@@ -1021,7 +1021,7 @@
}
func TestAndroidAppImport(t *testing.T) {
- ctx := testJava(t, `
+ ctx, _ := testJava(t, `
android_app_import {
name: "foo",
apk: "prebuilts/apk/app.apk",
@@ -1050,7 +1050,7 @@
}
func TestAndroidAppImport_NoDexPreopt(t *testing.T) {
- ctx := testJava(t, `
+ ctx, _ := testJava(t, `
android_app_import {
name: "foo",
apk: "prebuilts/apk/app.apk",
@@ -1071,7 +1071,7 @@
}
func TestAndroidAppImport_Presigned(t *testing.T) {
- ctx := testJava(t, `
+ ctx, _ := testJava(t, `
android_app_import {
name: "foo",
apk: "prebuilts/apk/app.apk",
@@ -1166,7 +1166,7 @@
config := testConfig(nil)
config.TestProductVariables.AAPTPreferredConfig = test.aaptPreferredConfig
config.TestProductVariables.AAPTPrebuiltDPI = test.aaptPrebuiltDPI
- ctx := testAppContext(config, bp, nil)
+ ctx := testAppContext(bp, nil)
run(t, ctx, config)
@@ -1183,7 +1183,7 @@
}
func TestStl(t *testing.T) {
- ctx := testJava(t, cc.GatherRequiredDepsForTest(android.Android)+`
+ ctx, _ := testJava(t, cc.GatherRequiredDepsForTest(android.Android)+`
cc_library {
name: "libjni",
}
@@ -1286,7 +1286,7 @@
config := testConfig(nil)
config.TestProductVariables.MissingUsesLibraries = []string{"baz"}
- ctx := testAppContext(config, bp, nil)
+ ctx := testAppContext(bp, nil)
run(t, ctx, config)
@@ -1398,7 +1398,7 @@
}
func TestEmbedNotice(t *testing.T) {
- ctx := testJava(t, cc.GatherRequiredDepsForTest(android.Android)+`
+ ctx, _ := testJava(t, cc.GatherRequiredDepsForTest(android.Android)+`
android_app {
name: "foo",
srcs: ["a.java"],
@@ -1549,7 +1549,7 @@
config.TestProductVariables.Unbundled_build = proptools.BoolPtr(true)
}
- ctx := testAppContext(config, bp, nil)
+ ctx := testAppContext(bp, nil)
run(t, ctx, config)
diff --git a/java/builder.go b/java/builder.go
index a48e8b1..22eff7c 100644
--- a/java/builder.go
+++ b/java/builder.go
@@ -148,16 +148,15 @@
}
type javaBuilderFlags struct {
- javacFlags string
- bootClasspath classpath
- classpath classpath
- processorPath classpath
- processor string
- systemModules classpath
- systemModulesDeps android.Paths
- aidlFlags string
- aidlDeps android.Paths
- javaVersion string
+ javacFlags string
+ bootClasspath classpath
+ classpath classpath
+ processorPath classpath
+ processor string
+ systemModules *systemModules
+ aidlFlags string
+ aidlDeps android.Paths
+ javaVersion string
errorProneExtraJavacFlags string
errorProneProcessorPath classpath
@@ -249,8 +248,9 @@
var bootClasspath string
if flags.javaVersion == "1.9" {
- deps = append(deps, flags.systemModulesDeps...)
- bootClasspath = flags.systemModules.FormJavaSystemModulesPath("--system=", ctx.Device())
+ var systemModuleDeps android.Paths
+ bootClasspath, systemModuleDeps = flags.systemModules.FormJavaSystemModulesPath(ctx.Device())
+ deps = append(deps, systemModuleDeps...)
} else {
deps = append(deps, flags.bootClasspath...)
if len(flags.bootClasspath) == 0 && ctx.Device() {
@@ -411,7 +411,7 @@
})
}
-type classpath []android.Path
+type classpath android.Paths
func (x *classpath) FormJavaClassPath(optName string) string {
if optName != "" && !strings.HasSuffix(optName, "=") && !strings.HasSuffix(optName, " ") {
@@ -424,21 +424,6 @@
}
}
-// Returns a --system argument in the form javac expects with -source 1.9. If forceEmpty is true,
-// returns --system=none if the list is empty to ensure javac does not fall back to the default
-// system modules.
-func (x *classpath) FormJavaSystemModulesPath(optName string, forceEmpty bool) string {
- if len(*x) > 1 {
- panic("more than one system module")
- } else if len(*x) == 1 {
- return optName + (*x)[0].String()
- } else if forceEmpty {
- return optName + "none"
- } else {
- return ""
- }
-}
-
func (x *classpath) FormTurbineClasspath(optName string) []string {
if x == nil || *x == nil {
return nil
@@ -466,3 +451,21 @@
}
return ret
}
+
+type systemModules struct {
+ dir android.Path
+ deps android.Paths
+}
+
+// Returns a --system argument in the form javac expects with -source 1.9. If forceEmpty is true,
+// returns --system=none if the list is empty to ensure javac does not fall back to the default
+// system modules.
+func (x *systemModules) FormJavaSystemModulesPath(forceEmpty bool) (string, android.Paths) {
+ if x != nil {
+ return "--system=" + x.dir.String(), x.deps
+ } else if forceEmpty {
+ return "--system=none", nil
+ } else {
+ return "", nil
+ }
+}
diff --git a/java/config/config.go b/java/config/config.go
index d017ae6..6a0a10a 100644
--- a/java/config/config.go
+++ b/java/config/config.go
@@ -47,6 +47,11 @@
}
)
+const (
+ JavaVmFlags = `-XX:OnError="cat hs_err_pid%p.log" -XX:CICompilerCount=6 -XX:+UseDynamicNumberOfGCThreads`
+ JavacVmFlags = `-J-XX:OnError="cat hs_err_pid%p.log" -J-XX:CICompilerCount=6 -J-XX:+UseDynamicNumberOfGCThreads`
+)
+
func init() {
pctx.Import("github.com/google/blueprint/bootstrap")
@@ -69,8 +74,9 @@
// b/65004097: prevent using java.lang.invoke.StringConcatFactory when using -target 1.9
`-XDstringConcat=inline`,
}, " "))
- pctx.StaticVariable("JavaVmFlags", "-XX:OnError=\"cat hs_err_pid%p.log\" -XX:CICompilerCount=6 -XX:+UseDynamicNumberOfGCThreads")
- pctx.StaticVariable("JavacVmFlags", "-J-XX:OnError=\"cat hs_err_pid%p.log\" -J-XX:CICompilerCount=6 -J-XX:+UseDynamicNumberOfGCThreads")
+
+ pctx.StaticVariable("JavaVmFlags", JavaVmFlags)
+ pctx.StaticVariable("JavacVmFlags", JavacVmFlags)
pctx.VariableConfigMethod("hostPrebuiltTag", android.Config.PrebuiltOS)
@@ -154,3 +160,41 @@
pctx.HostBinToolVariable("Class2Greylist", "class2greylist")
pctx.HostBinToolVariable("HiddenAPI", "hiddenapi")
}
+
+// JavaCmd returns a SourcePath object with the path to the java command.
+func JavaCmd(ctx android.PathContext) android.SourcePath {
+ return javaTool(ctx, "java")
+}
+
+// JavadocCmd returns a SourcePath object with the path to the java command.
+func JavadocCmd(ctx android.PathContext) android.SourcePath {
+ return javaTool(ctx, "javadoc")
+}
+
+func javaTool(ctx android.PathContext, tool string) android.SourcePath {
+ type javaToolKey string
+
+ key := android.NewCustomOnceKey(javaToolKey(tool))
+
+ return ctx.Config().OnceSourcePath(key, func() android.SourcePath {
+ return javaToolchain(ctx).Join(ctx, tool)
+ })
+
+}
+
+var javaToolchainKey = android.NewOnceKey("javaToolchain")
+
+func javaToolchain(ctx android.PathContext) android.SourcePath {
+ return ctx.Config().OnceSourcePath(javaToolchainKey, func() android.SourcePath {
+ return javaHome(ctx).Join(ctx, "bin")
+ })
+}
+
+var javaHomeKey = android.NewOnceKey("javaHome")
+
+func javaHome(ctx android.PathContext) android.SourcePath {
+ return ctx.Config().OnceSourcePath(javaHomeKey, func() android.SourcePath {
+ // This is set up and guaranteed by soong_ui
+ return android.PathForSource(ctx, ctx.Config().Getenv("ANDROID_JAVA_HOME"))
+ })
+}
diff --git a/java/device_host_converter_test.go b/java/device_host_converter_test.go
index 9b9d0d8..44aae9b 100644
--- a/java/device_host_converter_test.go
+++ b/java/device_host_converter_test.go
@@ -50,9 +50,7 @@
}
`
- config := testConfig(nil)
- ctx := testContext(config, bp, nil)
- run(t, ctx, config)
+ ctx, config := testJava(t, bp)
deviceModule := ctx.ModuleForTests("device_module", "android_common")
deviceTurbineCombined := deviceModule.Output("turbine-combined/device_module.jar")
@@ -133,9 +131,7 @@
}
`
- config := testConfig(nil)
- ctx := testContext(config, bp, nil)
- run(t, ctx, config)
+ ctx, config := testJava(t, bp)
hostModule := ctx.ModuleForTests("host_module", config.BuildOsCommonVariant)
hostJavac := hostModule.Output("javac/host_module.jar")
diff --git a/java/dexpreopt_bootjars.go b/java/dexpreopt_bootjars.go
index fe468a9..4ef5bcf 100644
--- a/java/dexpreopt_bootjars.go
+++ b/java/dexpreopt_bootjars.go
@@ -229,7 +229,7 @@
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 @@
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/dexpreopt_bootjars_test.go b/java/dexpreopt_bootjars_test.go
index f91ff69..4c38399 100644
--- a/java/dexpreopt_bootjars_test.go
+++ b/java/dexpreopt_bootjars_test.go
@@ -51,7 +51,7 @@
dexpreoptConfig.RuntimeApexJars = []string{"foo", "bar", "baz"}
setDexpreoptTestGlobalConfig(config, dexpreoptConfig)
- ctx := testContext(config, bp, nil)
+ ctx := testContext(bp, nil)
ctx.RegisterSingletonType("dex_bootjars", android.SingletonFactoryAdaptor(dexpreoptBootJarsFactory))
diff --git a/java/dexpreopt_test.go b/java/dexpreopt_test.go
index 7d0109f..22b7bb9 100644
--- a/java/dexpreopt_test.go
+++ b/java/dexpreopt_test.go
@@ -142,7 +142,7 @@
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
- ctx := testJava(t, test.bp)
+ ctx, _ := testJava(t, test.bp)
dexpreopt := ctx.ModuleForTests("foo", "android_common").MaybeDescription("dexpreopt")
enabled := dexpreopt.Rule != nil
diff --git a/java/droiddoc.go b/java/droiddoc.go
index 25101de..78bfa80 100644
--- a/java/droiddoc.go
+++ b/java/droiddoc.go
@@ -15,126 +15,15 @@
package java
import (
- "android/soong/android"
- "android/soong/java/config"
"fmt"
"path/filepath"
"runtime"
"strings"
- "github.com/google/blueprint"
"github.com/google/blueprint/proptools"
-)
-var (
- javadoc = pctx.AndroidStaticRule("javadoc",
- blueprint.RuleParams{
- Command: `rm -rf "$outDir" "$srcJarDir" "$stubsDir" && mkdir -p "$outDir" "$srcJarDir" "$stubsDir" && ` +
- `${config.ZipSyncCmd} -d $srcJarDir -l $srcJarDir/list -f "*.java" $srcJars && ` +
- `${config.SoongJavacWrapper} ${config.JavadocCmd} -encoding UTF-8 @$out.rsp @$srcJarDir/list ` +
- `$opts $bootclasspathArgs $classpathArgs $sourcepathArgs ` +
- `-d $outDir -quiet && ` +
- `${config.SoongZipCmd} -write_if_changed -d -o $docZip -C $outDir -D $outDir && ` +
- `${config.SoongZipCmd} -write_if_changed -jar -o $out -C $stubsDir -D $stubsDir $postDoclavaCmds && ` +
- `rm -rf "$srcJarDir"`,
-
- CommandDeps: []string{
- "${config.ZipSyncCmd}",
- "${config.JavadocCmd}",
- "${config.SoongZipCmd}",
- },
- CommandOrderOnly: []string{"${config.SoongJavacWrapper}"},
- Rspfile: "$out.rsp",
- RspfileContent: "$in",
- Restat: true,
- },
- "outDir", "srcJarDir", "stubsDir", "srcJars", "opts",
- "bootclasspathArgs", "classpathArgs", "sourcepathArgs", "docZip", "postDoclavaCmds")
-
- apiCheck = pctx.AndroidStaticRule("apiCheck",
- blueprint.RuleParams{
- Command: `( ${config.ApiCheckCmd} -JXmx1024m -J"classpath $classpath" $opts ` +
- `$apiFile $apiFileToCheck $removedApiFile $removedApiFileToCheck ` +
- `&& touch $out ) || (echo -e "$msg" ; exit 38)`,
- CommandDeps: []string{
- "${config.ApiCheckCmd}",
- },
- },
- "classpath", "opts", "apiFile", "apiFileToCheck", "removedApiFile", "removedApiFileToCheck", "msg")
-
- updateApi = pctx.AndroidStaticRule("updateApi",
- blueprint.RuleParams{
- Command: `( ( cp -f $srcApiFile $destApiFile && cp -f $srcRemovedApiFile $destRemovedApiFile ) ` +
- `&& touch $out ) || (echo failed to update public API ; exit 38)`,
- },
- "srcApiFile", "destApiFile", "srcRemovedApiFile", "destRemovedApiFile")
-
- metalava = pctx.AndroidStaticRule("metalava",
- blueprint.RuleParams{
- Command: `rm -rf "$outDir" "$srcJarDir" "$stubsDir" && ` +
- `mkdir -p "$outDir" "$srcJarDir" "$stubsDir" && ` +
- `${config.ZipSyncCmd} -d $srcJarDir -l $srcJarDir/list -f "*.java" $srcJars && ` +
- `${config.JavaCmd} ${config.JavaVmFlags} -jar ${config.MetalavaJar} -encoding UTF-8 -source $javaVersion @$out.rsp @$srcJarDir/list ` +
- `$bootclasspathArgs $classpathArgs $sourcepathArgs --no-banner --color --quiet --format=v2 ` +
- `$opts && ` +
- `${config.SoongZipCmd} -write_if_changed -jar -o $out -C $stubsDir -D $stubsDir && ` +
- `rm -rf "$srcJarDir"`,
- CommandDeps: []string{
- "${config.ZipSyncCmd}",
- "${config.JavaCmd}",
- "${config.MetalavaJar}",
- "${config.SoongZipCmd}",
- },
- Rspfile: "$out.rsp",
- RspfileContent: "$in",
- Restat: true,
- },
- "outDir", "srcJarDir", "stubsDir", "srcJars", "javaVersion", "bootclasspathArgs",
- "classpathArgs", "sourcepathArgs", "opts")
-
- metalavaApiCheck = pctx.AndroidStaticRule("metalavaApiCheck",
- blueprint.RuleParams{
- Command: `( rm -rf "$srcJarDir" && mkdir -p "$srcJarDir" && ` +
- `${config.ZipSyncCmd} -d $srcJarDir -l $srcJarDir/list -f "*.java" $srcJars && ` +
- `${config.JavaCmd} ${config.JavaVmFlags} -jar ${config.MetalavaJar} -encoding UTF-8 -source $javaVersion @$out.rsp @$srcJarDir/list ` +
- `$bootclasspathArgs $classpathArgs $sourcepathArgs --no-banner --color --quiet --format=v2 ` +
- `$opts && touch $out && rm -rf "$srcJarDir") || ` +
- `( echo -e "$msg" ; exit 38 )`,
- CommandDeps: []string{
- "${config.ZipSyncCmd}",
- "${config.JavaCmd}",
- "${config.MetalavaJar}",
- },
- Rspfile: "$out.rsp",
- RspfileContent: "$in",
- },
- "srcJarDir", "srcJars", "javaVersion", "bootclasspathArgs", "classpathArgs", "sourcepathArgs", "opts", "msg")
-
- nullabilityWarningsCheck = pctx.AndroidStaticRule("nullabilityWarningsCheck",
- blueprint.RuleParams{
- Command: `( diff $expected $actual && touch $out ) || ( echo -e "$msg" ; exit 38 )`,
- },
- "expected", "actual", "msg")
-
- dokka = pctx.AndroidStaticRule("dokka",
- blueprint.RuleParams{
- Command: `rm -rf "$outDir" "$srcJarDir" "$stubsDir" && ` +
- `mkdir -p "$outDir" "$srcJarDir" "$stubsDir" && ` +
- `${config.ZipSyncCmd} -d $srcJarDir -l $srcJarDir/list -f "*.java" $srcJars && ` +
- `${config.JavaCmd} ${config.JavaVmFlags} -jar ${config.DokkaJar} $srcJarDir ` +
- `$classpathArgs -format dac -dacRoot /reference/kotlin -output $outDir $opts && ` +
- `${config.SoongZipCmd} -write_if_changed -d -o $docZip -C $outDir -D $outDir && ` +
- `${config.SoongZipCmd} -write_if_changed -jar -o $out -C $stubsDir -D $stubsDir && ` +
- `rm -rf "$srcJarDir"`,
- CommandDeps: []string{
- "${config.ZipSyncCmd}",
- "${config.DokkaJar}",
- "${config.MetalavaJar}",
- "${config.SoongZipCmd}",
- },
- Restat: true,
- },
- "outDir", "srcJarDir", "stubsDir", "srcJars", "classpathArgs", "opts", "docZip")
+ "android/soong/android"
+ "android/soong/java/config"
)
func init() {
@@ -238,7 +127,7 @@
// proofread file contains all of the text content of the javadocs concatenated into one file,
// suitable for spell-checking and other goodness.
- Proofread_file *string `android:"path"`
+ Proofread_file *string
// a todo file lists the program elements that are missing documentation.
// At some point, this might be improved to show more warnings.
@@ -404,14 +293,6 @@
doclavaStubsFlags string
doclavaDocsFlags string
postDoclavaCmds string
-
- metalavaStubsFlags string
- metalavaAnnotationsFlags string
- metalavaMergeAnnoDirFlags string
- metalavaInclusionAnnotationsFlags string
- metalavaApiLevelsAnnotationsFlags string
-
- metalavaApiToXmlFlags string
}
func InitDroiddocModule(module android.DefaultableModule, hod android.HostOrDeviceSupported) {
@@ -454,23 +335,6 @@
ApiFilePath() android.Path
}
-func transformUpdateApi(ctx android.ModuleContext, destApiFile, destRemovedApiFile,
- srcApiFile, srcRemovedApiFile android.Path, output android.WritablePath) {
- ctx.Build(pctx, android.BuildParams{
- Rule: updateApi,
- Description: "Update API",
- Output: output,
- Implicits: append(android.Paths{}, srcApiFile, srcRemovedApiFile,
- destApiFile, destRemovedApiFile),
- Args: map[string]string{
- "destApiFile": destApiFile.String(),
- "srcApiFile": srcApiFile.String(),
- "destRemovedApiFile": destRemovedApiFile.String(),
- "srcRemovedApiFile": srcRemovedApiFile.String(),
- },
- })
-}
-
//
// Javadoc
//
@@ -500,6 +364,7 @@
}
}
+// javadoc converts .java source files to documentation using javadoc.
func JavadocFactory() android.Module {
module := &Javadoc{}
@@ -509,6 +374,7 @@
return module
}
+// javadoc_host converts .java source files to documentation using javadoc.
func JavadocHostFactory() android.Module {
module := &Javadoc{}
@@ -653,6 +519,7 @@
deps.classpath = append(deps.classpath, dep.SdkImplementationJars(ctx, j.sdkVersion())...)
case Dependency:
deps.classpath = append(deps.classpath, dep.HeaderJars()...)
+ deps.aidlIncludeDirs = append(deps.aidlIncludeDirs, dep.AidlIncludeDirs()...)
case android.SourceFileProducer:
checkProducesJars(ctx, dep)
deps.classpath = append(deps.classpath, dep.Srcs()...)
@@ -689,8 +556,7 @@
if sm.outputDir == nil && len(sm.outputDeps) == 0 {
panic("Missing directory for system module dependency")
}
- deps.systemModules = sm.outputDir
- deps.systemModulesDeps = sm.outputDeps
+ deps.systemModules = &systemModules{sm.outputDir, sm.outputDeps}
}
})
// do not pass exclude_srcs directly when expanding srcFiles since exclude_srcs
@@ -706,9 +572,6 @@
j.srcFiles = srcFiles.FilterOutByExt(".srcjar")
j.srcFiles = append(j.srcFiles, deps.srcs...)
- j.docZip = android.PathForModuleOut(ctx, ctx.ModuleName()+"-"+"docs.zip")
- j.stubsSrcJar = android.PathForModuleOut(ctx, ctx.ModuleName()+"-"+"stubs.srcjar")
-
if j.properties.Local_sourcepaths == nil && len(j.srcFiles) > 0 {
j.properties.Local_sourcepaths = append(j.properties.Local_sourcepaths, ".")
}
@@ -759,52 +622,43 @@
func (j *Javadoc) GenerateAndroidBuildActions(ctx android.ModuleContext) {
deps := j.collectDeps(ctx)
- var implicits android.Paths
- implicits = append(implicits, deps.bootClasspath...)
- implicits = append(implicits, deps.classpath...)
+ j.docZip = android.PathForModuleOut(ctx, ctx.ModuleName()+"-"+"docs.zip")
- var bootClasspathArgs, classpathArgs, sourcepathArgs string
+ outDir := android.PathForModuleOut(ctx, "out")
+ srcJarDir := android.PathForModuleOut(ctx, "srcjars")
+
+ j.stubsSrcJar = nil
+
+ rule := android.NewRuleBuilder()
+
+ rule.Command().Text("rm -rf").Text(outDir.String())
+ rule.Command().Text("mkdir -p").Text(outDir.String())
+
+ srcJarList := zipSyncCmd(ctx, rule, srcJarDir, j.srcJars)
javaVersion := getJavaVersion(ctx, String(j.properties.Java_version), sdkContext(j))
- if len(deps.bootClasspath) > 0 {
- var systemModules classpath
- if deps.systemModules != nil {
- systemModules = append(systemModules, deps.systemModules)
- }
- implicits = append(implicits, deps.systemModulesDeps...)
- bootClasspathArgs = systemModules.FormJavaSystemModulesPath("--system ", ctx.Device())
- bootClasspathArgs = bootClasspathArgs + " --patch-module java.base=."
- }
- if len(deps.classpath.Strings()) > 0 {
- classpathArgs = "-classpath " + strings.Join(deps.classpath.Strings(), ":")
- }
- implicits = append(implicits, j.srcJars...)
- implicits = append(implicits, j.argFiles...)
+ cmd := javadocSystemModulesCmd(ctx, rule, j.srcFiles, outDir, srcJarDir, srcJarList,
+ deps.systemModules, deps.classpath, j.sourcepaths)
- opts := "-source " + javaVersion + " -J-Xmx1024m -XDignore.symbol.file -Xdoclint:none"
+ cmd.FlagWithArg("-source ", javaVersion).
+ Flag("-J-Xmx1024m").
+ Flag("-XDignore.symbol.file").
+ Flag("-Xdoclint:none")
- sourcepathArgs = "-sourcepath " + strings.Join(j.sourcepaths.Strings(), ":")
+ rule.Command().
+ BuiltTool(ctx, "soong_zip").
+ Flag("-write_if_changed").
+ Flag("-d").
+ FlagWithOutput("-o ", j.docZip).
+ FlagWithArg("-C ", outDir.String()).
+ FlagWithArg("-D ", outDir.String())
- ctx.Build(pctx, android.BuildParams{
- Rule: javadoc,
- Description: "Javadoc",
- Output: j.stubsSrcJar,
- ImplicitOutput: j.docZip,
- Inputs: j.srcFiles,
- Implicits: implicits,
- Args: map[string]string{
- "outDir": android.PathForModuleOut(ctx, "out").String(),
- "srcJarDir": android.PathForModuleOut(ctx, "srcjars").String(),
- "stubsDir": android.PathForModuleOut(ctx, "stubsDir").String(),
- "srcJars": strings.Join(j.srcJars.Strings(), " "),
- "opts": opts,
- "bootclasspathArgs": bootClasspathArgs,
- "classpathArgs": classpathArgs,
- "sourcepathArgs": sourcepathArgs,
- "docZip": j.docZip.String(),
- },
- })
+ rule.Restat()
+
+ zipSyncCleanupCmd(rule, srcJarDir)
+
+ rule.Build(pctx, ctx, "javadoc", "javadoc")
}
//
@@ -831,6 +685,7 @@
apiFilePath android.Path
}
+// droiddoc converts .java source files to documentation using doclava or dokka.
func DroiddocFactory() android.Module {
module := &Droiddoc{}
@@ -841,6 +696,7 @@
return module
}
+// droiddoc_host converts .java source files to documentation using doclava or dokka.
func DroiddocHostFactory() android.Module {
module := &Droiddoc{}
@@ -867,58 +723,25 @@
}
}
-func (d *Droiddoc) initBuilderFlags(ctx android.ModuleContext, implicits *android.Paths,
- deps deps) (droiddocBuilderFlags, error) {
- var flags droiddocBuilderFlags
-
- *implicits = append(*implicits, deps.bootClasspath...)
- *implicits = append(*implicits, deps.classpath...)
-
- if len(deps.bootClasspath.Strings()) > 0 {
- // For OpenJDK 8 we can use -bootclasspath to define the core libraries code.
- flags.bootClasspathArgs = deps.bootClasspath.FormJavaClassPath("-bootclasspath")
- }
- flags.classpathArgs = deps.classpath.FormJavaClassPath("-classpath")
- // Dokka doesn't support bootClasspath, so combine these two classpath vars for Dokka.
- dokkaClasspath := classpath{}
- dokkaClasspath = append(dokkaClasspath, deps.bootClasspath...)
- dokkaClasspath = append(dokkaClasspath, deps.classpath...)
- flags.dokkaClasspathArgs = dokkaClasspath.FormJavaClassPath("-classpath")
-
- // TODO(nanzhang): Remove this if- statement once we finish migration for all Doclava
- // based stubs generation.
- // In the future, all the docs generation depends on Metalava stubs (droidstubs) srcjar
- // dir. We need add the srcjar dir to -sourcepath arg, so that Javadoc can figure out
- // the correct package name base path.
- if len(d.Javadoc.properties.Local_sourcepaths) > 0 {
- flags.sourcepathArgs = "-sourcepath " + strings.Join(d.Javadoc.sourcepaths.Strings(), ":")
- } else {
- flags.sourcepathArgs = "-sourcepath " + android.PathForModuleOut(ctx, "srcjars").String()
- }
-
- return flags, nil
-}
-
-func (d *Droiddoc) collectDoclavaDocsFlags(ctx android.ModuleContext, implicits *android.Paths,
- jsilver, doclava android.Path) string {
-
- *implicits = append(*implicits, jsilver)
- *implicits = append(*implicits, doclava)
-
+func (d *Droiddoc) doclavaDocsFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand, docletPath classpath) {
var date string
if runtime.GOOS == "darwin" {
date = `date -r`
} else {
- date = `date -d`
+ date = `date -d @`
}
// Droiddoc always gets "-source 1.8" because it doesn't support 1.9 sources. For modules with 1.9
// sources, droiddoc will get sources produced by metalava which will have already stripped out the
// 1.9 language features.
- 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")" `
+ cmd.FlagWithArg("-source ", "1.8").
+ Flag("-J-Xmx1600m").
+ Flag("-J-XX:-OmitStackTraceInFastThrow").
+ Flag("-XDignore.symbol.file").
+ FlagWithArg("-doclet ", "com.google.doclava.Doclava").
+ FlagWithInputList("-docletpath ", docletPath.Paths(), ":").
+ FlagWithArg("-hdf page.build ", ctx.Config().BuildId()+"-"+ctx.Config().BuildNumberFromFile()).
+ FlagWithArg("-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
@@ -927,23 +750,22 @@
ctx.VisitDirectDepsWithTag(droiddocTemplateTag, func(m android.Module) {
if t, ok := m.(*ExportedDroiddocDir); ok {
- *implicits = append(*implicits, t.deps...)
- args = args + " -templatedir " + t.dir.String()
+ cmd.FlagWithArg("-templatedir ", t.dir.String()).Implicits(t.deps)
} else {
ctx.PropertyErrorf("custom_template", "module %q is not a droiddoc_template", ctx.OtherModuleName(m))
}
})
if len(d.properties.Html_dirs) > 0 {
- htmlDir := d.properties.Html_dirs[0]
- *implicits = append(*implicits, android.PathsForModuleSrc(ctx, []string{filepath.Join(d.properties.Html_dirs[0], "**/*")})...)
- args = args + " -htmldir " + htmlDir
+ htmlDir := android.PathForModuleSrc(ctx, d.properties.Html_dirs[0])
+ cmd.FlagWithArg("-htmldir ", htmlDir.String()).
+ Implicits(android.PathsForModuleSrc(ctx, []string{filepath.Join(d.properties.Html_dirs[0], "**/*")}))
}
if len(d.properties.Html_dirs) > 1 {
- htmlDir2 := d.properties.Html_dirs[1]
- *implicits = append(*implicits, android.PathsForModuleSrc(ctx, []string{filepath.Join(htmlDir2, "**/*")})...)
- args = args + " -htmldir2 " + htmlDir2
+ htmlDir2 := android.PathForModuleSrc(ctx, d.properties.Html_dirs[1])
+ cmd.FlagWithArg("-htmldir2 ", htmlDir2.String()).
+ Implicits(android.PathsForModuleSrc(ctx, []string{filepath.Join(d.properties.Html_dirs[1], "**/*")}))
}
if len(d.properties.Html_dirs) > 2 {
@@ -951,51 +773,43 @@
}
knownTags := android.PathsForModuleSrc(ctx, d.properties.Knowntags)
- *implicits = append(*implicits, knownTags...)
+ cmd.FlagForEachInput("-knowntags ", knownTags)
- for _, kt := range knownTags {
- args = args + " -knowntags " + kt.String()
- }
-
- for _, hdf := range d.properties.Hdf {
- args = args + " -hdf " + hdf
- }
+ cmd.FlagForEachArg("-hdf ", d.properties.Hdf)
if String(d.properties.Proofread_file) != "" {
proofreadFile := android.PathForModuleOut(ctx, String(d.properties.Proofread_file))
- args = args + " -proofread " + proofreadFile.String()
+ cmd.FlagWithOutput("-proofread ", proofreadFile)
}
if String(d.properties.Todo_file) != "" {
// tricky part:
// we should not compute full path for todo_file through PathForModuleOut().
// the non-standard doclet will get the full path relative to "-o".
- args = args + " -todo " + String(d.properties.Todo_file)
+ cmd.FlagWithArg("-todo ", String(d.properties.Todo_file)).
+ ImplicitOutput(android.PathForModuleOut(ctx, String(d.properties.Todo_file)))
}
if String(d.properties.Resourcesdir) != "" {
// TODO: should we add files under resourcesDir to the implicits? It seems that
// resourcesDir is one sub dir of htmlDir
resourcesDir := android.PathForModuleSrc(ctx, String(d.properties.Resourcesdir))
- args = args + " -resourcesdir " + resourcesDir.String()
+ cmd.FlagWithArg("-resourcesdir ", resourcesDir.String())
}
if String(d.properties.Resourcesoutdir) != "" {
// TODO: it seems -resourceoutdir reference/android/images/ didn't get generated anywhere.
- args = args + " -resourcesoutdir " + String(d.properties.Resourcesoutdir)
+ cmd.FlagWithArg("-resourcesoutdir ", String(d.properties.Resourcesoutdir))
}
- return args
}
-func (d *Droiddoc) collectStubsFlags(ctx android.ModuleContext,
- implicitOutputs *android.WritablePaths) string {
- var doclavaFlags string
+func (d *Droiddoc) stubsFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand, stubsDir android.WritablePath) {
if apiCheckEnabled(d.properties.Check_api.Current, "current") ||
apiCheckEnabled(d.properties.Check_api.Last_released, "last_released") ||
String(d.properties.Api_filename) != "" {
+
d.apiFile = android.PathForModuleOut(ctx, ctx.ModuleName()+"_api.txt")
- doclavaFlags += " -api " + d.apiFile.String()
- *implicitOutputs = append(*implicitOutputs, d.apiFile)
+ cmd.FlagWithOutput("-api ", d.apiFile)
d.apiFilePath = d.apiFile
}
@@ -1003,223 +817,324 @@
apiCheckEnabled(d.properties.Check_api.Last_released, "last_released") ||
String(d.properties.Removed_api_filename) != "" {
d.removedApiFile = android.PathForModuleOut(ctx, ctx.ModuleName()+"_removed.txt")
- doclavaFlags += " -removedApi " + d.removedApiFile.String()
- *implicitOutputs = append(*implicitOutputs, d.removedApiFile)
+ cmd.FlagWithOutput("-removedApi ", d.removedApiFile)
}
if String(d.properties.Private_api_filename) != "" {
d.privateApiFile = android.PathForModuleOut(ctx, String(d.properties.Private_api_filename))
- doclavaFlags += " -privateApi " + d.privateApiFile.String()
- *implicitOutputs = append(*implicitOutputs, d.privateApiFile)
+ cmd.FlagWithOutput("-privateApi ", d.privateApiFile)
}
if String(d.properties.Dex_api_filename) != "" {
d.dexApiFile = android.PathForModuleOut(ctx, String(d.properties.Dex_api_filename))
- doclavaFlags += " -dexApi " + d.dexApiFile.String()
- *implicitOutputs = append(*implicitOutputs, d.dexApiFile)
+ cmd.FlagWithOutput("-dexApi ", d.dexApiFile)
}
if String(d.properties.Private_dex_api_filename) != "" {
d.privateDexApiFile = android.PathForModuleOut(ctx, String(d.properties.Private_dex_api_filename))
- doclavaFlags += " -privateDexApi " + d.privateDexApiFile.String()
- *implicitOutputs = append(*implicitOutputs, d.privateDexApiFile)
+ cmd.FlagWithOutput("-privateDexApi ", d.privateDexApiFile)
}
if String(d.properties.Removed_dex_api_filename) != "" {
d.removedDexApiFile = android.PathForModuleOut(ctx, String(d.properties.Removed_dex_api_filename))
- doclavaFlags += " -removedDexApi " + d.removedDexApiFile.String()
- *implicitOutputs = append(*implicitOutputs, d.removedDexApiFile)
+ cmd.FlagWithOutput("-removedDexApi ", d.removedDexApiFile)
}
if String(d.properties.Exact_api_filename) != "" {
d.exactApiFile = android.PathForModuleOut(ctx, String(d.properties.Exact_api_filename))
- doclavaFlags += " -exactApi " + d.exactApiFile.String()
- *implicitOutputs = append(*implicitOutputs, d.exactApiFile)
+ cmd.FlagWithOutput("-exactApi ", d.exactApiFile)
}
if String(d.properties.Dex_mapping_filename) != "" {
d.apiMappingFile = android.PathForModuleOut(ctx, String(d.properties.Dex_mapping_filename))
- doclavaFlags += " -apiMapping " + d.apiMappingFile.String()
- *implicitOutputs = append(*implicitOutputs, d.apiMappingFile)
+ cmd.FlagWithOutput("-apiMapping ", d.apiMappingFile)
}
if String(d.properties.Proguard_filename) != "" {
d.proguardFile = android.PathForModuleOut(ctx, String(d.properties.Proguard_filename))
- doclavaFlags += " -proguard " + d.proguardFile.String()
- *implicitOutputs = append(*implicitOutputs, d.proguardFile)
+ cmd.FlagWithOutput("-proguard ", d.proguardFile)
}
if BoolDefault(d.properties.Create_stubs, true) {
- doclavaFlags += " -stubs " + android.PathForModuleOut(ctx, "stubsDir").String()
+ cmd.FlagWithArg("-stubs ", stubsDir.String())
}
if Bool(d.properties.Write_sdk_values) {
- doclavaFlags += " -sdkvalues " + android.PathForModuleOut(ctx, "out").String()
+ cmd.FlagWithArg("-sdkvalues ", android.PathForModuleOut(ctx, "out").String())
}
-
- return doclavaFlags
}
-func (d *Droiddoc) getPostDoclavaCmds(ctx android.ModuleContext, implicits *android.Paths) string {
- var cmds string
+func (d *Droiddoc) postDoclavaCmds(ctx android.ModuleContext, rule *android.RuleBuilder) {
if String(d.properties.Static_doc_index_redirect) != "" {
- static_doc_index_redirect := ctx.ExpandSource(String(d.properties.Static_doc_index_redirect),
- "static_doc_index_redirect")
- *implicits = append(*implicits, static_doc_index_redirect)
- cmds = cmds + " && cp " + static_doc_index_redirect.String() + " " +
- android.PathForModuleOut(ctx, "out", "index.html").String()
+ staticDocIndexRedirect := android.PathForModuleSrc(ctx, String(d.properties.Static_doc_index_redirect))
+ rule.Command().Text("cp").
+ Input(staticDocIndexRedirect).
+ Output(android.PathForModuleOut(ctx, "out", "index.html"))
}
if String(d.properties.Static_doc_properties) != "" {
- static_doc_properties := ctx.ExpandSource(String(d.properties.Static_doc_properties),
- "static_doc_properties")
- *implicits = append(*implicits, static_doc_properties)
- cmds = cmds + " && cp " + static_doc_properties.String() + " " +
- android.PathForModuleOut(ctx, "out", "source.properties").String()
+ staticDocProperties := android.PathForModuleSrc(ctx, String(d.properties.Static_doc_properties))
+ rule.Command().Text("cp").
+ Input(staticDocProperties).
+ Output(android.PathForModuleOut(ctx, "out", "source.properties"))
}
- return cmds
}
-func (d *Droiddoc) transformDoclava(ctx android.ModuleContext, implicits android.Paths,
- implicitOutputs android.WritablePaths,
- bootclasspathArgs, classpathArgs, sourcepathArgs, opts, postDoclavaCmds string) {
- ctx.Build(pctx, android.BuildParams{
- Rule: javadoc,
- Description: "Doclava",
- Output: d.Javadoc.stubsSrcJar,
- Inputs: d.Javadoc.srcFiles,
- Implicits: implicits,
- ImplicitOutputs: implicitOutputs,
- Args: map[string]string{
- "outDir": android.PathForModuleOut(ctx, "out").String(),
- "srcJarDir": android.PathForModuleOut(ctx, "srcjars").String(),
- "stubsDir": android.PathForModuleOut(ctx, "stubsDir").String(),
- "srcJars": strings.Join(d.Javadoc.srcJars.Strings(), " "),
- "opts": opts,
- "bootclasspathArgs": bootclasspathArgs,
- "classpathArgs": classpathArgs,
- "sourcepathArgs": sourcepathArgs,
- "docZip": d.Javadoc.docZip.String(),
- "postDoclavaCmds": postDoclavaCmds,
- },
- })
+func javadocCmd(ctx android.ModuleContext, rule *android.RuleBuilder, srcs android.Paths,
+ outDir, srcJarDir, srcJarList android.Path, sourcepaths android.Paths) *android.RuleBuilderCommand {
+
+ cmd := rule.Command().
+ BuiltTool(ctx, "soong_javac_wrapper").Tool(config.JavadocCmd(ctx)).
+ Flag(config.JavacVmFlags).
+ FlagWithArg("-encoding ", "UTF-8").
+ FlagWithRspFileInputList("@", srcs).
+ FlagWithInput("@", srcJarList)
+
+ // TODO(ccross): Remove this if- statement once we finish migration for all Doclava
+ // based stubs generation.
+ // In the future, all the docs generation depends on Metalava stubs (droidstubs) srcjar
+ // dir. We need add the srcjar dir to -sourcepath arg, so that Javadoc can figure out
+ // the correct package name base path.
+ if len(sourcepaths) > 0 {
+ cmd.FlagWithList("-sourcepath ", sourcepaths.Strings(), ":")
+ } else {
+ cmd.FlagWithArg("-sourcepath ", srcJarDir.String())
+ }
+
+ cmd.FlagWithArg("-d ", outDir.String()).
+ Flag("-quiet")
+
+ return cmd
}
-func (d *Droiddoc) transformCheckApi(ctx android.ModuleContext, apiFile, removedApiFile android.Path,
- checkApiClasspath classpath, msg, opts string, output android.WritablePath) {
- ctx.Build(pctx, android.BuildParams{
- Rule: apiCheck,
- Description: "Doclava Check API",
- Output: output,
- Inputs: nil,
- Implicits: append(android.Paths{apiFile, removedApiFile, d.apiFile, d.removedApiFile},
- checkApiClasspath...),
- Args: map[string]string{
- "msg": msg,
- "classpath": checkApiClasspath.FormJavaClassPath(""),
- "opts": opts,
- "apiFile": apiFile.String(),
- "apiFileToCheck": d.apiFile.String(),
- "removedApiFile": removedApiFile.String(),
- "removedApiFileToCheck": d.removedApiFile.String(),
- },
- })
+func javadocSystemModulesCmd(ctx android.ModuleContext, rule *android.RuleBuilder, srcs android.Paths,
+ outDir, srcJarDir, srcJarList android.Path, systemModules *systemModules,
+ classpath classpath, sourcepaths android.Paths) *android.RuleBuilderCommand {
+
+ cmd := javadocCmd(ctx, rule, srcs, outDir, srcJarDir, srcJarList, sourcepaths)
+
+ flag, deps := systemModules.FormJavaSystemModulesPath(ctx.Device())
+ cmd.Flag(flag).Implicits(deps)
+
+ cmd.FlagWithArg("--patch-module ", "java.base=.")
+
+ if len(classpath) > 0 {
+ cmd.FlagWithInputList("-classpath ", classpath.Paths(), ":")
+ }
+
+ return cmd
}
-func (d *Droiddoc) transformDokka(ctx android.ModuleContext, implicits android.Paths,
- classpathArgs, opts string) {
- ctx.Build(pctx, android.BuildParams{
- Rule: dokka,
- Description: "Dokka",
- Output: d.Javadoc.stubsSrcJar,
- Inputs: d.Javadoc.srcFiles,
- Implicits: implicits,
- Args: map[string]string{
- "outDir": android.PathForModuleOut(ctx, "dokka-out").String(),
- "srcJarDir": android.PathForModuleOut(ctx, "dokka-srcjars").String(),
- "stubsDir": android.PathForModuleOut(ctx, "dokka-stubsDir").String(),
- "srcJars": strings.Join(d.Javadoc.srcJars.Strings(), " "),
- "classpathArgs": classpathArgs,
- "opts": opts,
- "docZip": d.Javadoc.docZip.String(),
- },
- })
+func javadocBootclasspathCmd(ctx android.ModuleContext, rule *android.RuleBuilder, srcs android.Paths,
+ outDir, srcJarDir, srcJarList android.Path, bootclasspath, classpath classpath,
+ sourcepaths android.Paths) *android.RuleBuilderCommand {
+
+ cmd := javadocCmd(ctx, rule, srcs, outDir, srcJarDir, srcJarList, sourcepaths)
+
+ if len(bootclasspath) == 0 && ctx.Device() {
+ // explicitly specify -bootclasspath "" if the bootclasspath is empty to
+ // ensure java does not fall back to the default bootclasspath.
+ cmd.FlagWithArg("-bootclasspath ", `""`)
+ } else if len(bootclasspath) > 0 {
+ cmd.FlagWithInputList("-bootclasspath ", bootclasspath.Paths(), ":")
+ }
+
+ if len(classpath) > 0 {
+ cmd.FlagWithInputList("-classpath ", classpath.Paths(), ":")
+ }
+
+ return cmd
+}
+
+func dokkaCmd(ctx android.ModuleContext, rule *android.RuleBuilder,
+ outDir, srcJarDir android.Path, bootclasspath, classpath classpath) *android.RuleBuilderCommand {
+
+ // Dokka doesn't support bootClasspath, so combine these two classpath vars for Dokka.
+ dokkaClasspath := append(bootclasspath.Paths(), classpath.Paths()...)
+
+ return rule.Command().
+ BuiltTool(ctx, "dokka").
+ Flag(config.JavacVmFlags).
+ Flag(srcJarDir.String()).
+ FlagWithInputList("-classpath ", dokkaClasspath, ":").
+ FlagWithArg("-format ", "dac").
+ FlagWithArg("-dacRoot ", "/reference/kotlin").
+ FlagWithArg("-output ", outDir.String())
}
func (d *Droiddoc) GenerateAndroidBuildActions(ctx android.ModuleContext) {
deps := d.Javadoc.collectDeps(ctx)
+ d.Javadoc.docZip = android.PathForModuleOut(ctx, ctx.ModuleName()+"-"+"docs.zip")
+ d.Javadoc.stubsSrcJar = android.PathForModuleOut(ctx, ctx.ModuleName()+"-"+"stubs.srcjar")
+
jsilver := android.PathForOutput(ctx, "host", ctx.Config().PrebuiltOS(), "framework", "jsilver.jar")
doclava := android.PathForOutput(ctx, "host", ctx.Config().PrebuiltOS(), "framework", "doclava.jar")
java8Home := ctx.Config().Getenv("ANDROID_JAVA8_HOME")
checkApiClasspath := classpath{jsilver, doclava, android.PathForSource(ctx, java8Home, "lib/tools.jar")}
- var implicits android.Paths
- implicits = append(implicits, d.Javadoc.srcJars...)
- implicits = append(implicits, d.Javadoc.argFiles...)
+ outDir := android.PathForModuleOut(ctx, "out")
+ srcJarDir := android.PathForModuleOut(ctx, "srcjars")
+ stubsDir := android.PathForModuleOut(ctx, "stubsDir")
- var implicitOutputs android.WritablePaths
- implicitOutputs = append(implicitOutputs, d.Javadoc.docZip)
- for _, o := range d.Javadoc.properties.Out {
- implicitOutputs = append(implicitOutputs, android.PathForModuleGen(ctx, o))
- }
+ rule := android.NewRuleBuilder()
- flags, err := d.initBuilderFlags(ctx, &implicits, deps)
- if err != nil {
- return
- }
+ rule.Command().Text("rm -rf").Text(outDir.String()).Text(stubsDir.String())
+ rule.Command().Text("mkdir -p").Text(outDir.String()).Text(stubsDir.String())
- flags.doclavaStubsFlags = d.collectStubsFlags(ctx, &implicitOutputs)
+ srcJarList := zipSyncCmd(ctx, rule, srcJarDir, d.Javadoc.srcJars)
+
+ var cmd *android.RuleBuilderCommand
if Bool(d.properties.Dokka_enabled) {
- d.transformDokka(ctx, implicits, flags.classpathArgs, d.Javadoc.args)
+ cmd = dokkaCmd(ctx, rule, outDir, srcJarDir, deps.bootClasspath, deps.classpath)
} else {
- flags.doclavaDocsFlags = d.collectDoclavaDocsFlags(ctx, &implicits, jsilver, doclava)
- flags.postDoclavaCmds = d.getPostDoclavaCmds(ctx, &implicits)
- d.transformDoclava(ctx, implicits, implicitOutputs, flags.bootClasspathArgs, flags.classpathArgs,
- flags.sourcepathArgs, flags.doclavaDocsFlags+flags.doclavaStubsFlags+" "+d.Javadoc.args,
- flags.postDoclavaCmds)
+ cmd = javadocBootclasspathCmd(ctx, rule, d.Javadoc.srcFiles, outDir, srcJarDir, srcJarList,
+ deps.bootClasspath, deps.classpath, d.Javadoc.sourcepaths)
}
+ d.stubsFlags(ctx, cmd, stubsDir)
+
+ cmd.Flag(d.Javadoc.args).Implicits(d.Javadoc.argFiles)
+
+ var desc string
+ if Bool(d.properties.Dokka_enabled) {
+ desc = "dokka"
+ } else {
+ d.doclavaDocsFlags(ctx, cmd, classpath{jsilver, doclava})
+
+ for _, o := range d.Javadoc.properties.Out {
+ cmd.ImplicitOutput(android.PathForModuleGen(ctx, o))
+ }
+
+ d.postDoclavaCmds(ctx, rule)
+ desc = "doclava"
+ }
+
+ rule.Command().
+ BuiltTool(ctx, "soong_zip").
+ Flag("-write_if_changed").
+ Flag("-d").
+ FlagWithOutput("-o ", d.docZip).
+ FlagWithArg("-C ", outDir.String()).
+ FlagWithArg("-D ", outDir.String())
+
+ rule.Command().
+ BuiltTool(ctx, "soong_zip").
+ Flag("-write_if_changed").
+ Flag("-jar").
+ FlagWithOutput("-o ", d.stubsSrcJar).
+ FlagWithArg("-C ", stubsDir.String()).
+ FlagWithArg("-D ", stubsDir.String())
+
+ rule.Restat()
+
+ zipSyncCleanupCmd(rule, srcJarDir)
+
+ rule.Build(pctx, ctx, "javadoc", desc)
+
if apiCheckEnabled(d.properties.Check_api.Current, "current") &&
!ctx.Config().IsPdkBuild() {
- apiFile := ctx.ExpandSource(String(d.properties.Check_api.Current.Api_file),
- "check_api.current.api_file")
- removedApiFile := ctx.ExpandSource(String(d.properties.Check_api.Current.Removed_api_file),
- "check_api.current_removed_api_file")
+
+ apiFile := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Current.Api_file))
+ removedApiFile := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Current.Removed_api_file))
d.checkCurrentApiTimestamp = android.PathForModuleOut(ctx, "check_current_api.timestamp")
- d.transformCheckApi(ctx, apiFile, removedApiFile, checkApiClasspath,
- fmt.Sprintf(`\n******************************\n`+
- `You have tried to change the API from what has been previously approved.\n\n`+
- `To make these errors go away, you have two choices:\n`+
- ` 1. You can add '@hide' javadoc comments to the methods, etc. listed in the\n`+
- ` errors above.\n\n`+
- ` 2. You can update current.txt by executing the following command:\n`+
- ` make %s-update-current-api\n\n`+
- ` To submit the revised current.txt to the main Android repository,\n`+
- ` you will need approval.\n`+
- `******************************\n`, ctx.ModuleName()), String(d.properties.Check_api.Current.Args),
- d.checkCurrentApiTimestamp)
+
+ rule := android.NewRuleBuilder()
+
+ rule.Command().Text("( true")
+
+ rule.Command().
+ BuiltTool(ctx, "apicheck").
+ Flag("-JXmx1024m").
+ FlagWithInputList("-Jclasspath\\ ", checkApiClasspath.Paths(), ":").
+ OptionalFlag(d.properties.Check_api.Current.Args).
+ Input(apiFile).
+ Input(d.apiFile).
+ Input(removedApiFile).
+ Input(d.removedApiFile)
+
+ msg := fmt.Sprintf(`\n******************************\n`+
+ `You have tried to change the API from what has been previously approved.\n\n`+
+ `To make these errors go away, you have two choices:\n`+
+ ` 1. You can add '@hide' javadoc comments to the methods, etc. listed in the\n`+
+ ` errors above.\n\n`+
+ ` 2. You can update current.txt by executing the following command:\n`+
+ ` make %s-update-current-api\n\n`+
+ ` To submit the revised current.txt to the main Android repository,\n`+
+ ` you will need approval.\n`+
+ `******************************\n`, ctx.ModuleName())
+
+ rule.Command().
+ Text("touch").Output(d.checkCurrentApiTimestamp).
+ Text(") || (").
+ Text("echo").Flag("-e").Flag(`"` + msg + `"`).
+ Text("; exit 38").
+ Text(")")
+
+ rule.Build(pctx, ctx, "doclavaCurrentApiCheck", "check current API")
d.updateCurrentApiTimestamp = android.PathForModuleOut(ctx, "update_current_api.timestamp")
- transformUpdateApi(ctx, apiFile, removedApiFile, d.apiFile, d.removedApiFile,
- d.updateCurrentApiTimestamp)
+
+ // update API rule
+ rule = android.NewRuleBuilder()
+
+ rule.Command().Text("( true")
+
+ rule.Command().
+ Text("cp").Flag("-f").
+ Input(d.apiFile).Flag(apiFile.String())
+
+ rule.Command().
+ Text("cp").Flag("-f").
+ Input(d.removedApiFile).Flag(removedApiFile.String())
+
+ msg = "failed to update public API"
+
+ rule.Command().
+ Text("touch").Output(d.updateCurrentApiTimestamp).
+ Text(") || (").
+ Text("echo").Flag("-e").Flag(`"` + msg + `"`).
+ Text("; exit 38").
+ Text(")")
+
+ rule.Build(pctx, ctx, "doclavaCurrentApiUpdate", "update current API")
}
if apiCheckEnabled(d.properties.Check_api.Last_released, "last_released") &&
!ctx.Config().IsPdkBuild() {
- apiFile := ctx.ExpandSource(String(d.properties.Check_api.Last_released.Api_file),
- "check_api.last_released.api_file")
- removedApiFile := ctx.ExpandSource(String(d.properties.Check_api.Last_released.Removed_api_file),
- "check_api.last_released.removed_api_file")
+
+ apiFile := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Last_released.Api_file))
+ removedApiFile := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Last_released.Removed_api_file))
d.checkLastReleasedApiTimestamp = android.PathForModuleOut(ctx, "check_last_released_api.timestamp")
- d.transformCheckApi(ctx, apiFile, removedApiFile, checkApiClasspath,
- `\n******************************\n`+
- `You have tried to change the API from what has been previously released in\n`+
- `an SDK. Please fix the errors listed above.\n`+
- `******************************\n`, String(d.properties.Check_api.Last_released.Args),
- d.checkLastReleasedApiTimestamp)
+
+ rule := android.NewRuleBuilder()
+
+ rule.Command().
+ Text("(").
+ BuiltTool(ctx, "apicheck").
+ Flag("-JXmx1024m").
+ FlagWithInputList("-Jclasspath\\ ", checkApiClasspath.Paths(), ":").
+ OptionalFlag(d.properties.Check_api.Last_released.Args).
+ Input(apiFile).
+ Input(d.apiFile).
+ Input(removedApiFile).
+ Input(d.removedApiFile)
+
+ msg := `\n******************************\n` +
+ `You have tried to change the API from what has been previously released in\n` +
+ `an SDK. Please fix the errors listed above.\n` +
+ `******************************\n`
+
+ rule.Command().
+ Text("touch").Output(d.checkLastReleasedApiTimestamp).
+ Text(") || (").
+ Text("echo").Flag("-e").Flag(`"` + msg + `"`).
+ Text("; exit 38").
+ Text(")")
+
+ rule.Build(pctx, ctx, "doclavaLastApiCheck", "check last API")
}
}
@@ -1258,6 +1173,9 @@
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 +1186,10 @@
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{}
@@ -1308,34 +1230,12 @@
}
}
-func (d *Droidstubs) initBuilderFlags(ctx android.ModuleContext, implicits *android.Paths,
- deps deps) (droiddocBuilderFlags, error) {
- var flags droiddocBuilderFlags
-
- *implicits = append(*implicits, deps.bootClasspath...)
- *implicits = append(*implicits, deps.classpath...)
-
- // continue to use -bootclasspath even if Metalava under -source 1.9 is enabled
- // since it doesn't support system modules yet.
- if len(deps.bootClasspath.Strings()) > 0 {
- // For OpenJDK 8 we can use -bootclasspath to define the core libraries code.
- flags.bootClasspathArgs = deps.bootClasspath.FormJavaClassPath("-bootclasspath")
- }
- flags.classpathArgs = deps.classpath.FormJavaClassPath("-classpath")
-
- flags.sourcepathArgs = "-sourcepath \"" + strings.Join(d.Javadoc.sourcepaths.Strings(), ":") + "\""
- return flags, nil
-}
-
-func (d *Droidstubs) collectStubsFlags(ctx android.ModuleContext,
- implicitOutputs *android.WritablePaths) string {
- var metalavaFlags string
+func (d *Droidstubs) stubsFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand, stubsDir android.WritablePath) {
if apiCheckEnabled(d.properties.Check_api.Current, "current") ||
apiCheckEnabled(d.properties.Check_api.Last_released, "last_released") ||
String(d.properties.Api_filename) != "" {
d.apiFile = android.PathForModuleOut(ctx, ctx.ModuleName()+"_api.txt")
- metalavaFlags = metalavaFlags + " --api " + d.apiFile.String()
- *implicitOutputs = append(*implicitOutputs, d.apiFile)
+ cmd.FlagWithOutput("--api ", d.apiFile)
d.apiFilePath = d.apiFile
}
@@ -1343,159 +1243,144 @@
apiCheckEnabled(d.properties.Check_api.Last_released, "last_released") ||
String(d.properties.Removed_api_filename) != "" {
d.removedApiFile = android.PathForModuleOut(ctx, ctx.ModuleName()+"_removed.txt")
- metalavaFlags = metalavaFlags + " --removed-api " + d.removedApiFile.String()
- *implicitOutputs = append(*implicitOutputs, d.removedApiFile)
+ cmd.FlagWithOutput("--removed-api ", d.removedApiFile)
}
if String(d.properties.Private_api_filename) != "" {
d.privateApiFile = android.PathForModuleOut(ctx, String(d.properties.Private_api_filename))
- metalavaFlags = metalavaFlags + " --private-api " + d.privateApiFile.String()
- *implicitOutputs = append(*implicitOutputs, d.privateApiFile)
+ cmd.FlagWithOutput("--private-api ", d.privateApiFile)
}
if String(d.properties.Dex_api_filename) != "" {
d.dexApiFile = android.PathForModuleOut(ctx, String(d.properties.Dex_api_filename))
- metalavaFlags += " --dex-api " + d.dexApiFile.String()
- *implicitOutputs = append(*implicitOutputs, d.dexApiFile)
+ cmd.FlagWithOutput("--dex-api ", d.dexApiFile)
}
if String(d.properties.Private_dex_api_filename) != "" {
d.privateDexApiFile = android.PathForModuleOut(ctx, String(d.properties.Private_dex_api_filename))
- metalavaFlags = metalavaFlags + " --private-dex-api " + d.privateDexApiFile.String()
- *implicitOutputs = append(*implicitOutputs, d.privateDexApiFile)
+ cmd.FlagWithOutput("--private-dex-api ", d.privateDexApiFile)
}
if String(d.properties.Removed_dex_api_filename) != "" {
d.removedDexApiFile = android.PathForModuleOut(ctx, String(d.properties.Removed_dex_api_filename))
- metalavaFlags = metalavaFlags + " --removed-dex-api " + d.removedDexApiFile.String()
- *implicitOutputs = append(*implicitOutputs, d.removedDexApiFile)
+ cmd.FlagWithOutput("--removed-dex-api ", d.removedDexApiFile)
}
if String(d.properties.Exact_api_filename) != "" {
d.exactApiFile = android.PathForModuleOut(ctx, String(d.properties.Exact_api_filename))
- metalavaFlags = metalavaFlags + " --exact-api " + d.exactApiFile.String()
- *implicitOutputs = append(*implicitOutputs, d.exactApiFile)
+ cmd.FlagWithOutput("--exact-api ", d.exactApiFile)
}
if String(d.properties.Dex_mapping_filename) != "" {
d.apiMappingFile = android.PathForModuleOut(ctx, String(d.properties.Dex_mapping_filename))
- metalavaFlags = metalavaFlags + " --dex-api-mapping " + d.apiMappingFile.String()
- *implicitOutputs = append(*implicitOutputs, d.apiMappingFile)
+ cmd.FlagWithOutput("--dex-api-mapping ", d.apiMappingFile)
}
if String(d.properties.Proguard_filename) != "" {
d.proguardFile = android.PathForModuleOut(ctx, String(d.properties.Proguard_filename))
- metalavaFlags += " --proguard " + d.proguardFile.String()
- *implicitOutputs = append(*implicitOutputs, d.proguardFile)
+ cmd.FlagWithOutput("--proguard ", d.proguardFile)
}
if Bool(d.properties.Write_sdk_values) {
- metalavaFlags = metalavaFlags + " --sdk-values " + android.PathForModuleOut(ctx, "out").String()
+ cmd.FlagWithArg("--sdk-values ", android.PathForModuleOut(ctx, "out").String())
}
if Bool(d.properties.Create_doc_stubs) {
- metalavaFlags += " --doc-stubs " + android.PathForModuleOut(ctx, "stubsDir").String()
+ cmd.FlagWithArg("--doc-stubs ", stubsDir.String())
} else {
- metalavaFlags += " --stubs " + android.PathForModuleOut(ctx, "stubsDir").String()
+ cmd.FlagWithArg("--stubs ", stubsDir.String())
}
- return metalavaFlags
}
-func (d *Droidstubs) collectAnnotationsFlags(ctx android.ModuleContext,
- implicits *android.Paths, implicitOutputs *android.WritablePaths) (string, string) {
- var flags, mergeAnnoDirFlags string
+func (d *Droidstubs) annotationsFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand) {
if Bool(d.properties.Annotations_enabled) {
- flags += " --include-annotations"
+ cmd.Flag("--include-annotations")
+
validatingNullability :=
strings.Contains(d.Javadoc.args, "--validate-nullability-from-merged-stubs") ||
String(d.properties.Validate_nullability_from_list) != ""
migratingNullability := String(d.properties.Previous_api) != ""
+
if !(migratingNullability || validatingNullability) {
ctx.PropertyErrorf("previous_api",
"has to be non-empty if annotations was enabled (unless validating nullability)")
}
+
if migratingNullability {
previousApi := android.PathForModuleSrc(ctx, String(d.properties.Previous_api))
- *implicits = append(*implicits, previousApi)
- flags += " --migrate-nullness " + previousApi.String()
+ cmd.FlagWithInput("--migrate-nullness ", previousApi)
}
+
if s := String(d.properties.Validate_nullability_from_list); s != "" {
- flags += " --validate-nullability-from-list " + android.PathForModuleSrc(ctx, s).String()
+ cmd.FlagWithInput("--validate-nullability-from-list ", android.PathForModuleSrc(ctx, s))
}
+
if validatingNullability {
d.nullabilityWarningsFile = android.PathForModuleOut(ctx, ctx.ModuleName()+"_nullability_warnings.txt")
- *implicitOutputs = append(*implicitOutputs, d.nullabilityWarningsFile)
- flags += " --nullability-warnings-txt " + d.nullabilityWarningsFile.String()
+ cmd.FlagWithOutput("--nullability-warnings-txt ", d.nullabilityWarningsFile)
}
d.annotationsZip = android.PathForModuleOut(ctx, ctx.ModuleName()+"_annotations.zip")
- *implicitOutputs = append(*implicitOutputs, d.annotationsZip)
-
- flags += " --extract-annotations " + d.annotationsZip.String()
+ cmd.FlagWithOutput("--extract-annotations ", d.annotationsZip)
if len(d.properties.Merge_annotations_dirs) == 0 {
ctx.PropertyErrorf("merge_annotations_dirs",
"has to be non-empty if annotations was enabled!")
}
- ctx.VisitDirectDepsWithTag(metalavaMergeAnnotationsDirTag, func(m android.Module) {
- if t, ok := m.(*ExportedDroiddocDir); ok {
- *implicits = append(*implicits, t.deps...)
- mergeAnnoDirFlags += " --merge-qualifier-annotations " + t.dir.String()
- } else {
- ctx.PropertyErrorf("merge_annotations_dirs",
- "module %q is not a metalava merge-annotations dir", ctx.OtherModuleName(m))
- }
- })
- flags += mergeAnnoDirFlags
- // TODO(tnorbye): find owners to fix these warnings when annotation was enabled.
- flags += " --hide HiddenTypedefConstant --hide SuperfluousPrefix --hide AnnotationExtraction"
- }
- return flags, mergeAnnoDirFlags
+ d.mergeAnnoDirFlags(ctx, cmd)
+
+ // TODO(tnorbye): find owners to fix these warnings when annotation was enabled.
+ cmd.FlagWithArg("--hide ", "HiddenTypedefConstant").
+ FlagWithArg("--hide ", "SuperfluousPrefix").
+ FlagWithArg("--hide ", "AnnotationExtraction")
+ }
}
-func (d *Droidstubs) collectInclusionAnnotationsFlags(ctx android.ModuleContext,
- implicits *android.Paths, implicitOutputs *android.WritablePaths) string {
- var flags string
+func (d *Droidstubs) mergeAnnoDirFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand) {
+ ctx.VisitDirectDepsWithTag(metalavaMergeAnnotationsDirTag, func(m android.Module) {
+ if t, ok := m.(*ExportedDroiddocDir); ok {
+ cmd.FlagWithArg("--merge-qualifier-annotations ", t.dir.String()).Implicits(t.deps)
+ } else {
+ ctx.PropertyErrorf("merge_annotations_dirs",
+ "module %q is not a metalava merge-annotations dir", ctx.OtherModuleName(m))
+ }
+ })
+}
+
+func (d *Droidstubs) inclusionAnnotationsFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand) {
ctx.VisitDirectDepsWithTag(metalavaMergeInclusionAnnotationsDirTag, func(m android.Module) {
if t, ok := m.(*ExportedDroiddocDir); ok {
- *implicits = append(*implicits, t.deps...)
- flags += " --merge-inclusion-annotations " + t.dir.String()
+ cmd.FlagWithArg("--merge-inclusion-annotations ", t.dir.String()).Implicits(t.deps)
} else {
ctx.PropertyErrorf("merge_inclusion_annotations_dirs",
"module %q is not a metalava merge-annotations dir", ctx.OtherModuleName(m))
}
})
-
- return flags
}
-func (d *Droidstubs) collectAPILevelsAnnotationsFlags(ctx android.ModuleContext,
- implicits *android.Paths, implicitOutputs *android.WritablePaths) string {
- var flags string
+func (d *Droidstubs) apiLevelsAnnotationsFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand) {
if Bool(d.properties.Api_levels_annotations_enabled) {
d.apiVersionsXml = android.PathForModuleOut(ctx, "api-versions.xml")
- *implicitOutputs = append(*implicitOutputs, d.apiVersionsXml)
if len(d.properties.Api_levels_annotations_dirs) == 0 {
ctx.PropertyErrorf("api_levels_annotations_dirs",
"has to be non-empty if api levels annotations was enabled!")
}
- flags = " --generate-api-levels " + d.apiVersionsXml.String() + " --apply-api-levels " +
- d.apiVersionsXml.String() + " --current-version " + ctx.Config().PlatformSdkVersion() +
- " --current-codename " + ctx.Config().PlatformSdkCodename() + " "
+ cmd.FlagWithOutput("--generate-api-levels ", d.apiVersionsXml)
+ cmd.FlagWithInput("--apply-api-levels ", d.apiVersionsXml)
+ cmd.FlagWithArg("--current-version ", ctx.Config().PlatformSdkVersion())
+ cmd.FlagWithArg("--current-codename ", ctx.Config().PlatformSdkCodename())
ctx.VisitDirectDepsWithTag(metalavaAPILevelsAnnotationsDirTag, func(m android.Module) {
if t, ok := m.(*ExportedDroiddocDir); ok {
- var androidJars android.Paths
for _, dep := range t.deps {
if strings.HasSuffix(dep.String(), "android.jar") {
- androidJars = append(androidJars, dep)
+ cmd.Implicit(dep)
}
}
- *implicits = append(*implicits, androidJars...)
- flags += " --android-jar-pattern " + t.dir.String() + "/%/public/android.jar "
+ cmd.FlagWithArg("--android-jar-pattern ", t.dir.String()+"/%/public/android.jar")
} else {
ctx.PropertyErrorf("api_levels_annotations_dirs",
"module %q is not a metalava api-levels-annotations dir", ctx.OtherModuleName(m))
@@ -1503,112 +1388,57 @@
})
}
-
- return flags
}
-func (d *Droidstubs) collectApiToXmlFlags(ctx android.ModuleContext, implicits *android.Paths,
- implicitOutputs *android.WritablePaths) string {
- var flags string
+func (d *Droidstubs) apiToXmlFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand) {
if Bool(d.properties.Jdiff_enabled) && !ctx.Config().IsPdkBuild() {
if d.apiFile.String() == "" {
ctx.ModuleErrorf("API signature file has to be specified in Metalava when jdiff is enabled.")
}
d.apiXmlFile = android.PathForModuleOut(ctx, ctx.ModuleName()+"_api.xml")
- *implicitOutputs = append(*implicitOutputs, d.apiXmlFile)
-
- flags = " --api-xml " + d.apiXmlFile.String()
+ cmd.FlagWithOutput("--api-xml ", d.apiXmlFile)
if String(d.properties.Check_api.Last_released.Api_file) == "" {
ctx.PropertyErrorf("check_api.last_released.api_file",
"has to be non-empty if jdiff was enabled!")
}
- lastReleasedApi := ctx.ExpandSource(String(d.properties.Check_api.Last_released.Api_file),
- "check_api.last_released.api_file")
- *implicits = append(*implicits, lastReleasedApi)
+ lastReleasedApi := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Last_released.Api_file))
d.lastReleasedApiXmlFile = android.PathForModuleOut(ctx, ctx.ModuleName()+"_last_released_api.xml")
- *implicitOutputs = append(*implicitOutputs, d.lastReleasedApiXmlFile)
+ cmd.FlagWithInput("--convert-to-jdiff ", lastReleasedApi).Output(d.lastReleasedApiXmlFile)
+ }
+}
- flags += " --convert-to-jdiff " + lastReleasedApi.String() + " " +
- d.lastReleasedApiXmlFile.String()
+func metalavaCmd(ctx android.ModuleContext, rule *android.RuleBuilder, javaVersion string, srcs android.Paths,
+ srcJarList android.Path, bootclasspath, classpath classpath, sourcepaths android.Paths) *android.RuleBuilderCommand {
+ cmd := rule.Command().BuiltTool(ctx, "metalava").
+ Flag(config.JavacVmFlags).
+ FlagWithArg("-encoding ", "UTF-8").
+ FlagWithArg("-source ", javaVersion).
+ FlagWithRspFileInputList("@", srcs).
+ FlagWithInput("@", srcJarList)
+
+ if len(bootclasspath) > 0 {
+ cmd.FlagWithInputList("-bootclasspath ", bootclasspath.Paths(), ":")
}
- return flags
-}
+ if len(classpath) > 0 {
+ cmd.FlagWithInputList("-classpath ", classpath.Paths(), ":")
+ }
-func (d *Droidstubs) transformMetalava(ctx android.ModuleContext, implicits android.Paths,
- implicitOutputs android.WritablePaths, javaVersion,
- bootclasspathArgs, classpathArgs, sourcepathArgs, opts string) {
+ if len(sourcepaths) > 0 {
+ cmd.FlagWithList("-sourcepath ", sourcepaths.Strings(), ":")
+ } else {
+ cmd.FlagWithArg("-sourcepath ", `""`)
+ }
- ctx.Build(pctx, android.BuildParams{
- Rule: metalava,
- Description: "Metalava",
- Output: d.Javadoc.stubsSrcJar,
- Inputs: d.Javadoc.srcFiles,
- Implicits: implicits,
- ImplicitOutputs: implicitOutputs,
- Args: map[string]string{
- "outDir": android.PathForModuleOut(ctx, "out").String(),
- "srcJarDir": android.PathForModuleOut(ctx, "srcjars").String(),
- "stubsDir": android.PathForModuleOut(ctx, "stubsDir").String(),
- "srcJars": strings.Join(d.Javadoc.srcJars.Strings(), " "),
- "javaVersion": javaVersion,
- "bootclasspathArgs": bootclasspathArgs,
- "classpathArgs": classpathArgs,
- "sourcepathArgs": sourcepathArgs,
- "opts": opts,
- },
- })
-}
+ cmd.Flag("--no-banner").
+ Flag("--color").
+ Flag("--quiet").
+ Flag("--format=v2")
-func (d *Droidstubs) transformCheckApi(ctx android.ModuleContext,
- apiFile, removedApiFile android.Path, implicits android.Paths,
- javaVersion, bootclasspathArgs, classpathArgs, sourcepathArgs, opts, subdir, msg string,
- output android.WritablePath) {
- ctx.Build(pctx, android.BuildParams{
- Rule: metalavaApiCheck,
- Description: "Metalava Check API",
- Output: output,
- Inputs: d.Javadoc.srcFiles,
- Implicits: append(android.Paths{apiFile, removedApiFile, d.apiFile, d.removedApiFile},
- implicits...),
- Args: map[string]string{
- "srcJarDir": android.PathForModuleOut(ctx, subdir, "srcjars").String(),
- "srcJars": strings.Join(d.Javadoc.srcJars.Strings(), " "),
- "javaVersion": javaVersion,
- "bootclasspathArgs": bootclasspathArgs,
- "classpathArgs": classpathArgs,
- "sourcepathArgs": sourcepathArgs,
- "opts": opts,
- "msg": msg,
- },
- })
-}
-
-func (d *Droidstubs) transformJdiff(ctx android.ModuleContext, implicits android.Paths,
- implicitOutputs android.WritablePaths,
- bootclasspathArgs, classpathArgs, sourcepathArgs, opts string) {
- ctx.Build(pctx, android.BuildParams{
- Rule: javadoc,
- Description: "Jdiff",
- Output: d.jdiffStubsSrcJar,
- Inputs: d.Javadoc.srcFiles,
- Implicits: implicits,
- ImplicitOutputs: implicitOutputs,
- Args: map[string]string{
- "outDir": android.PathForModuleOut(ctx, "jdiff-out").String(),
- "srcJarDir": android.PathForModuleOut(ctx, "jdiff-srcjars").String(),
- "stubsDir": android.PathForModuleOut(ctx, "jdiff-stubsDir").String(),
- "srcJars": strings.Join(d.Javadoc.srcJars.Strings(), " "),
- "opts": opts,
- "bootclasspathArgs": bootclasspathArgs,
- "classpathArgs": classpathArgs,
- "sourcepathArgs": sourcepathArgs,
- "docZip": d.jdiffDocZip.String(),
- },
- })
+ return cmd
}
func (d *Droidstubs) GenerateAndroidBuildActions(ctx android.ModuleContext) {
@@ -1616,29 +1446,29 @@
javaVersion := getJavaVersion(ctx, String(d.Javadoc.properties.Java_version), sdkContext(d))
- var implicits android.Paths
- implicits = append(implicits, d.Javadoc.srcJars...)
- implicits = append(implicits, d.Javadoc.argFiles...)
+ // Create rule for metalava
- var implicitOutputs android.WritablePaths
- for _, o := range d.Javadoc.properties.Out {
- implicitOutputs = append(implicitOutputs, android.PathForModuleGen(ctx, o))
- }
+ d.Javadoc.stubsSrcJar = android.PathForModuleOut(ctx, ctx.ModuleName()+"-"+"stubs.srcjar")
- flags, err := d.initBuilderFlags(ctx, &implicits, deps)
- metalavaCheckApiImplicits := implicits
- jdiffImplicits := implicits
+ srcJarDir := android.PathForModuleOut(ctx, "srcjars")
+ stubsDir := android.PathForModuleOut(ctx, "stubsDir")
- if err != nil {
- return
- }
+ rule := android.NewRuleBuilder()
- flags.metalavaStubsFlags = d.collectStubsFlags(ctx, &implicitOutputs)
- flags.metalavaAnnotationsFlags, flags.metalavaMergeAnnoDirFlags =
- d.collectAnnotationsFlags(ctx, &implicits, &implicitOutputs)
- flags.metalavaInclusionAnnotationsFlags = d.collectInclusionAnnotationsFlags(ctx, &implicits, &implicitOutputs)
- flags.metalavaApiLevelsAnnotationsFlags = d.collectAPILevelsAnnotationsFlags(ctx, &implicits, &implicitOutputs)
- flags.metalavaApiToXmlFlags = d.collectApiToXmlFlags(ctx, &implicits, &implicitOutputs)
+ rule.Command().Text("rm -rf").Text(stubsDir.String())
+ rule.Command().Text("mkdir -p").Text(stubsDir.String())
+
+ srcJarList := zipSyncCmd(ctx, rule, srcJarDir, d.Javadoc.srcJars)
+
+ cmd := metalavaCmd(ctx, rule, javaVersion, d.Javadoc.srcFiles, srcJarList,
+ deps.bootClasspath, deps.classpath, d.Javadoc.sourcepaths)
+
+ d.stubsFlags(ctx, cmd, stubsDir)
+
+ d.annotationsFlags(ctx, cmd)
+ d.inclusionAnnotationsFlags(ctx, cmd)
+ d.apiLevelsAnnotationsFlags(ctx, cmd)
+ d.apiToXmlFlags(ctx, cmd)
if strings.Contains(d.Javadoc.args, "--generate-documentation") {
// Currently Metalava have the ability to invoke Javadoc in a seperate process.
@@ -1646,61 +1476,150 @@
// "--generate-documentation" arg. This is not needed when Metalava removes this feature.
d.Javadoc.args = d.Javadoc.args + " -nodocs "
}
- d.transformMetalava(ctx, implicits, implicitOutputs, javaVersion,
- flags.bootClasspathArgs, flags.classpathArgs, flags.sourcepathArgs,
- flags.metalavaStubsFlags+flags.metalavaAnnotationsFlags+flags.metalavaInclusionAnnotationsFlags+
- flags.metalavaApiLevelsAnnotationsFlags+flags.metalavaApiToXmlFlags+" "+d.Javadoc.args)
+
+ cmd.Flag(d.Javadoc.args).Implicits(d.Javadoc.argFiles)
+ for _, o := range d.Javadoc.properties.Out {
+ cmd.ImplicitOutput(android.PathForModuleGen(ctx, o))
+ }
+
+ rule.Command().
+ BuiltTool(ctx, "soong_zip").
+ Flag("-write_if_changed").
+ Flag("-jar").
+ FlagWithOutput("-o ", d.Javadoc.stubsSrcJar).
+ FlagWithArg("-C ", stubsDir.String()).
+ FlagWithArg("-D ", stubsDir.String())
+ rule.Restat()
+
+ zipSyncCleanupCmd(rule, srcJarDir)
+
+ rule.Build(pctx, ctx, "metalava", "metalava")
+
+ // Create rule for apicheck
if apiCheckEnabled(d.properties.Check_api.Current, "current") &&
!ctx.Config().IsPdkBuild() {
- apiFile := ctx.ExpandSource(String(d.properties.Check_api.Current.Api_file),
- "check_api.current.api_file")
- removedApiFile := ctx.ExpandSource(String(d.properties.Check_api.Current.Removed_api_file),
- "check_api.current_removed_api_file")
+
+ if len(d.Javadoc.properties.Out) > 0 {
+ ctx.PropertyErrorf("out", "out property may not be combined with check_api")
+ }
+
+ apiFile := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Current.Api_file))
+ removedApiFile := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Current.Removed_api_file))
d.checkCurrentApiTimestamp = android.PathForModuleOut(ctx, "check_current_api.timestamp")
- opts := " " + d.Javadoc.args + " --check-compatibility:api:current " + apiFile.String() +
- " --check-compatibility:removed:current " + removedApiFile.String() +
- flags.metalavaInclusionAnnotationsFlags + flags.metalavaMergeAnnoDirFlags + " "
- d.transformCheckApi(ctx, apiFile, removedApiFile, metalavaCheckApiImplicits,
- javaVersion, flags.bootClasspathArgs, flags.classpathArgs, flags.sourcepathArgs, opts, "current-apicheck",
- fmt.Sprintf(`\n******************************\n`+
- `You have tried to change the API from what has been previously approved.\n\n`+
- `To make these errors go away, you have two choices:\n`+
- ` 1. You can add '@hide' javadoc comments to the methods, etc. listed in the\n`+
- ` errors above.\n\n`+
- ` 2. You can update current.txt by executing the following command:\n`+
- ` make %s-update-current-api\n\n`+
- ` To submit the revised current.txt to the main Android repository,\n`+
- ` you will need approval.\n`+
- `******************************\n`, ctx.ModuleName()),
- d.checkCurrentApiTimestamp)
+ rule := android.NewRuleBuilder()
+
+ rule.Command().Text("( true")
+
+ srcJarDir := android.PathForModuleOut(ctx, "current-apicheck", "srcjars")
+ srcJarList := zipSyncCmd(ctx, rule, srcJarDir, d.Javadoc.srcJars)
+
+ cmd := metalavaCmd(ctx, rule, javaVersion, d.Javadoc.srcFiles, srcJarList,
+ deps.bootClasspath, deps.classpath, d.Javadoc.sourcepaths)
+
+ cmd.Flag(d.Javadoc.args).Implicits(d.Javadoc.argFiles).
+ FlagWithInput("--check-compatibility:api:current ", apiFile).
+ FlagWithInput("--check-compatibility:removed:current ", removedApiFile)
+
+ d.inclusionAnnotationsFlags(ctx, cmd)
+ d.mergeAnnoDirFlags(ctx, cmd)
+
+ zipSyncCleanupCmd(rule, srcJarDir)
+
+ msg := fmt.Sprintf(`\n******************************\n`+
+ `You have tried to change the API from what has been previously approved.\n\n`+
+ `To make these errors go away, you have two choices:\n`+
+ ` 1. You can add '@hide' javadoc comments to the methods, etc. listed in the\n`+
+ ` errors above.\n\n`+
+ ` 2. You can update current.txt by executing the following command:\n`+
+ ` make %s-update-current-api\n\n`+
+ ` To submit the revised current.txt to the main Android repository,\n`+
+ ` you will need approval.\n`+
+ `******************************\n`, ctx.ModuleName())
+
+ rule.Command().
+ Text("touch").Output(d.checkCurrentApiTimestamp).
+ Text(") || (").
+ Text("echo").Flag("-e").Flag(`"` + msg + `"`).
+ Text("; exit 38").
+ Text(")")
+
+ rule.Build(pctx, ctx, "metalavaCurrentApiCheck", "metalava check current API")
d.updateCurrentApiTimestamp = android.PathForModuleOut(ctx, "update_current_api.timestamp")
- transformUpdateApi(ctx, apiFile, removedApiFile, d.apiFile, d.removedApiFile,
- d.updateCurrentApiTimestamp)
+
+ // update API rule
+ rule = android.NewRuleBuilder()
+
+ rule.Command().Text("( true")
+
+ rule.Command().
+ Text("cp").Flag("-f").
+ Input(d.apiFile).Flag(apiFile.String())
+
+ rule.Command().
+ Text("cp").Flag("-f").
+ Input(d.removedApiFile).Flag(removedApiFile.String())
+
+ msg = "failed to update public API"
+
+ rule.Command().
+ Text("touch").Output(d.updateCurrentApiTimestamp).
+ Text(") || (").
+ Text("echo").Flag("-e").Flag(`"` + msg + `"`).
+ Text("; exit 38").
+ Text(")")
+
+ rule.Build(pctx, ctx, "metalavaCurrentApiUpdate", "update current API")
}
if apiCheckEnabled(d.properties.Check_api.Last_released, "last_released") &&
!ctx.Config().IsPdkBuild() {
- apiFile := ctx.ExpandSource(String(d.properties.Check_api.Last_released.Api_file),
- "check_api.last_released.api_file")
- removedApiFile := ctx.ExpandSource(String(d.properties.Check_api.Last_released.Removed_api_file),
- "check_api.last_released.removed_api_file")
+
+ if len(d.Javadoc.properties.Out) > 0 {
+ ctx.PropertyErrorf("out", "out property may not be combined with check_api")
+ }
+
+ apiFile := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Last_released.Api_file))
+ removedApiFile := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Last_released.Removed_api_file))
d.checkLastReleasedApiTimestamp = android.PathForModuleOut(ctx, "check_last_released_api.timestamp")
- opts := " " + d.Javadoc.args + " --check-compatibility:api:released " + apiFile.String() +
- flags.metalavaInclusionAnnotationsFlags + " --check-compatibility:removed:released " +
- removedApiFile.String() + flags.metalavaMergeAnnoDirFlags + " "
- d.transformCheckApi(ctx, apiFile, removedApiFile, metalavaCheckApiImplicits,
- javaVersion, flags.bootClasspathArgs, flags.classpathArgs, flags.sourcepathArgs, opts, "last-apicheck",
- `\n******************************\n`+
- `You have tried to change the API from what has been previously released in\n`+
- `an SDK. Please fix the errors listed above.\n`+
- `******************************\n`,
- d.checkLastReleasedApiTimestamp)
+ rule := android.NewRuleBuilder()
+
+ rule.Command().Text("( true")
+
+ srcJarDir := android.PathForModuleOut(ctx, "last-apicheck", "srcjars")
+ srcJarList := zipSyncCmd(ctx, rule, srcJarDir, d.Javadoc.srcJars)
+
+ cmd := metalavaCmd(ctx, rule, javaVersion, d.Javadoc.srcFiles, srcJarList,
+ deps.bootClasspath, deps.classpath, d.Javadoc.sourcepaths)
+
+ cmd.Flag(d.Javadoc.args).Implicits(d.Javadoc.argFiles).
+ FlagWithInput("--check-compatibility:api:released ", apiFile)
+
+ d.inclusionAnnotationsFlags(ctx, cmd)
+
+ cmd.FlagWithInput("--check-compatibility:removed:released ", removedApiFile)
+
+ d.mergeAnnoDirFlags(ctx, cmd)
+
+ zipSyncCleanupCmd(rule, srcJarDir)
+
+ msg := `\n******************************\n` +
+ `You have tried to change the API from what has been previously released in\n` +
+ `an SDK. Please fix the errors listed above.\n` +
+ `******************************\n`
+ rule.Command().
+ Text("touch").Output(d.checkLastReleasedApiTimestamp).
+ Text(") || (").
+ Text("echo").Flag("-e").Flag(`"` + msg + `"`).
+ Text("; exit 38").
+ Text(")")
+
+ rule.Build(pctx, ctx, "metalavaLastApiCheck", "metalava check last API")
}
if String(d.properties.Check_nullability_warnings) != "" {
@@ -1708,9 +1627,11 @@
ctx.PropertyErrorf("check_nullability_warnings",
"Cannot specify check_nullability_warnings unless validating nullability")
}
- checkNullabilityWarnings := ctx.ExpandSource(String(d.properties.Check_nullability_warnings),
- "check_nullability_warnings")
+
+ checkNullabilityWarnings := android.PathForModuleSrc(ctx, String(d.properties.Check_nullability_warnings))
+
d.checkNullabilityWarningsTimestamp = android.PathForModuleOut(ctx, "check_nullability_warnings.timestamp")
+
msg := fmt.Sprintf(`\n******************************\n`+
`The warnings encountered during nullability annotation validation did\n`+
`not match the checked in file of expected warnings. The diffs are shown\n`+
@@ -1720,20 +1641,32 @@
` cp %s %s\n`+
` and submitting the updated file as part of your change.`,
d.nullabilityWarningsFile, checkNullabilityWarnings)
- ctx.Build(pctx, android.BuildParams{
- Rule: nullabilityWarningsCheck,
- Description: "Nullability Warnings Check",
- Output: d.checkNullabilityWarningsTimestamp,
- Implicits: android.Paths{checkNullabilityWarnings, d.nullabilityWarningsFile},
- Args: map[string]string{
- "expected": checkNullabilityWarnings.String(),
- "actual": d.nullabilityWarningsFile.String(),
- "msg": msg,
- },
- })
+
+ rule := android.NewRuleBuilder()
+
+ rule.Command().
+ Text("(").
+ Text("diff").Input(checkNullabilityWarnings).Input(d.nullabilityWarningsFile).
+ Text("&&").
+ Text("touch").Output(d.checkNullabilityWarningsTimestamp).
+ Text(") || (").
+ Text("echo").Flag("-e").Flag(`"` + msg + `"`).
+ Text("; exit 38").
+ Text(")")
+
+ rule.Build(pctx, ctx, "nullabilityWarningsCheck", "nullability warnings check")
}
if Bool(d.properties.Jdiff_enabled) && !ctx.Config().IsPdkBuild() {
+ if len(d.Javadoc.properties.Out) > 0 {
+ ctx.PropertyErrorf("out", "out property may not be combined with jdiff")
+ }
+
+ outDir := android.PathForModuleOut(ctx, "jdiff-out")
+ srcJarDir := android.PathForModuleOut(ctx, "jdiff-srcjars")
+ stubsDir := android.PathForModuleOut(ctx, "jdiff-stubsDir")
+
+ rule := android.NewRuleBuilder()
// Please sync with android-api-council@ before making any changes for the name of jdiffDocZip below
// since there's cron job downstream that fetch this .zip file periodically.
@@ -1741,21 +1674,49 @@
d.jdiffDocZip = android.PathForModuleOut(ctx, ctx.ModuleName()+"-"+"jdiff-docs.zip")
d.jdiffStubsSrcJar = android.PathForModuleOut(ctx, ctx.ModuleName()+"-"+"jdiff-stubs.srcjar")
- var jdiffImplicitOutputs android.WritablePaths
- jdiffImplicitOutputs = append(jdiffImplicitOutputs, d.jdiffDocZip)
-
jdiff := android.PathForOutput(ctx, "host", ctx.Config().PrebuiltOS(), "framework", "jdiff.jar")
- jdiffImplicits = append(jdiffImplicits, android.Paths{jdiff, d.apiXmlFile, d.lastReleasedApiXmlFile}...)
- opts := " -source 1.8 -J-Xmx1600m -XDignore.symbol.file " +
- "-doclet jdiff.JDiff -docletpath " + jdiff.String() + " -quiet " +
- "-newapi " + strings.TrimSuffix(d.apiXmlFile.Base(), d.apiXmlFile.Ext()) +
- " -newapidir " + filepath.Dir(d.apiXmlFile.String()) +
- " -oldapi " + strings.TrimSuffix(d.lastReleasedApiXmlFile.Base(), d.lastReleasedApiXmlFile.Ext()) +
- " -oldapidir " + filepath.Dir(d.lastReleasedApiXmlFile.String())
+ rule.Command().Text("rm -rf").Text(outDir.String()).Text(stubsDir.String())
+ rule.Command().Text("mkdir -p").Text(outDir.String()).Text(stubsDir.String())
- d.transformJdiff(ctx, jdiffImplicits, jdiffImplicitOutputs, flags.bootClasspathArgs, flags.classpathArgs,
- flags.sourcepathArgs, opts)
+ srcJarList := zipSyncCmd(ctx, rule, srcJarDir, d.Javadoc.srcJars)
+
+ cmd := javadocBootclasspathCmd(ctx, rule, d.Javadoc.srcFiles, outDir, srcJarDir, srcJarList,
+ deps.bootClasspath, deps.classpath, d.sourcepaths)
+
+ cmd.Flag("-J-Xmx1600m").
+ Flag("-XDignore.symbol.file").
+ FlagWithArg("-doclet ", "jdiff.JDiff").
+ FlagWithInput("-docletpath ", jdiff).
+ Flag("-quiet").
+ FlagWithArg("-newapi ", strings.TrimSuffix(d.apiXmlFile.Base(), d.apiXmlFile.Ext())).
+ FlagWithArg("-newapidir ", filepath.Dir(d.apiXmlFile.String())).
+ Implicit(d.apiXmlFile).
+ FlagWithArg("-oldapi ", strings.TrimSuffix(d.lastReleasedApiXmlFile.Base(), d.lastReleasedApiXmlFile.Ext())).
+ FlagWithArg("-oldapidir ", filepath.Dir(d.lastReleasedApiXmlFile.String())).
+ Implicit(d.lastReleasedApiXmlFile)
+
+ rule.Command().
+ BuiltTool(ctx, "soong_zip").
+ Flag("-write_if_changed").
+ Flag("-d").
+ FlagWithOutput("-o ", d.jdiffDocZip).
+ FlagWithArg("-C ", outDir.String()).
+ FlagWithArg("-D ", outDir.String())
+
+ rule.Command().
+ BuiltTool(ctx, "soong_zip").
+ Flag("-write_if_changed").
+ Flag("-jar").
+ FlagWithOutput("-o ", d.jdiffStubsSrcJar).
+ FlagWithArg("-C ", stubsDir.String()).
+ FlagWithArg("-D ", stubsDir.String())
+
+ rule.Restat()
+
+ zipSyncCleanupCmd(rule, srcJarDir)
+
+ rule.Build(pctx, ctx, "jdiff", "jdiff")
}
}
@@ -1781,6 +1742,7 @@
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)
@@ -1829,3 +1791,25 @@
return module
}
+
+func zipSyncCmd(ctx android.ModuleContext, rule *android.RuleBuilder,
+ srcJarDir android.ModuleOutPath, srcJars android.Paths) android.OutputPath {
+
+ rule.Command().Text("rm -rf").Text(srcJarDir.String())
+ rule.Command().Text("mkdir -p").Text(srcJarDir.String())
+ srcJarList := srcJarDir.Join(ctx, "list")
+
+ rule.Temporary(srcJarList)
+
+ rule.Command().BuiltTool(ctx, "zipsync").
+ FlagWithArg("-d ", srcJarDir.String()).
+ FlagWithOutput("-l ", srcJarList).
+ FlagWithArg("-f ", `"*.java"`).
+ Inputs(srcJars)
+
+ return srcJarList
+}
+
+func zipSyncCleanupCmd(rule *android.RuleBuilder, srcJarDir android.ModuleOutPath) {
+ rule.Command().Text("rm -rf").Text(srcJarDir.String())
+}
diff --git a/java/gen.go b/java/gen.go
index b1c028d..69965ec 100644
--- a/java/gen.go
+++ b/java/gen.go
@@ -15,6 +15,8 @@
package java
import (
+ "strings"
+
"github.com/google/blueprint"
"android/soong/android"
@@ -63,6 +65,10 @@
func genAidl(ctx android.ModuleContext, aidlFile android.Path, aidlFlags string, deps android.Paths) android.Path {
javaFile := android.GenPathWithExt(ctx, "aidl", aidlFile, "java")
depFile := javaFile.String() + ".d"
+ baseDir := strings.TrimSuffix(aidlFile.String(), aidlFile.Rel())
+ if baseDir != "" {
+ aidlFlags += " -I" + baseDir
+ }
ctx.Build(pctx, android.BuildParams{
Rule: aidl,
diff --git a/java/java.go b/java/java.go
index 318a36b..f3e10be 100644
--- a/java/java.go
+++ b/java/java.go
@@ -632,8 +632,7 @@
aidlIncludeDirs android.Paths
srcs android.Paths
srcJars android.Paths
- systemModules android.Path
- systemModulesDeps android.Paths
+ systemModules *systemModules
aidlPreprocess android.OptionalPath
kotlinStdlib android.Paths
kotlinAnnotations android.Paths
@@ -844,8 +843,7 @@
if sm.outputDir == nil || len(sm.outputDeps) == 0 {
panic("Missing directory for system module dependency")
}
- deps.systemModules = sm.outputDir
- deps.systemModulesDeps = sm.outputDeps
+ deps.systemModules = &systemModules{sm.outputDir, sm.outputDeps}
}
}
})
@@ -973,10 +971,7 @@
}
// systemModules
- if deps.systemModules != nil {
- flags.systemModules = append(flags.systemModules, deps.systemModules)
- flags.systemModulesDeps = append(flags.systemModulesDeps, deps.systemModulesDeps...)
- }
+ flags.systemModules = deps.systemModules
// aidl flags.
flags.aidlFlags, flags.aidlDeps = j.aidlFlags(ctx, deps.aidlPreprocess, deps.aidlIncludeDirs)
@@ -2040,7 +2035,7 @@
// dex_import module
type DexImportProperties struct {
- Jars []string
+ Jars []string `android:"path"`
}
type DexImport struct {
@@ -2068,10 +2063,6 @@
return j.prebuilt.Name(j.ModuleBase.Name())
}
-func (j *DexImport) DepsMutator(ctx android.BottomUpMutatorContext) {
- android.ExtractSourcesDeps(ctx, j.properties.Jars)
-}
-
func (j *DexImport) GenerateAndroidBuildActions(ctx android.ModuleContext) {
if len(j.properties.Jars) != 1 {
ctx.PropertyErrorf("jars", "exactly one jar must be provided")
@@ -2092,14 +2083,14 @@
// 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/java_test.go b/java/java_test.go
index 677174d..f95f88b 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -57,8 +57,7 @@
return TestConfig(buildDir, env)
}
-func testContext(config android.Config, bp string,
- fs map[string][]byte) *android.TestContext {
+func testContext(bp string, fs map[string][]byte) *android.TestContext {
ctx := android.NewTestArchContext()
ctx.RegisterModuleType("android_app", android.ModuleFactoryAdaptor(AndroidAppFactory))
@@ -193,6 +192,7 @@
"bar-doc/a.java": nil,
"bar-doc/b.java": nil,
"bar-doc/IFoo.aidl": nil,
+ "bar-doc/IBar.aidl": nil,
"bar-doc/known_oj_tags.txt": nil,
"external/doclava/templates-sdk": nil,
@@ -222,13 +222,13 @@
android.FailIfErrored(t, errs)
}
-func testJava(t *testing.T, bp string) *android.TestContext {
+func testJava(t *testing.T, bp string) (*android.TestContext, android.Config) {
t.Helper()
config := testConfig(nil)
- ctx := testContext(config, bp, nil)
+ ctx := testContext(bp, nil)
run(t, ctx, config)
- return ctx
+ return ctx, config
}
func moduleToPath(name string) string {
@@ -243,7 +243,7 @@
}
func TestSimple(t *testing.T) {
- ctx := testJava(t, `
+ ctx, _ := testJava(t, `
java_library {
name: "foo",
srcs: ["a.java"],
@@ -287,7 +287,7 @@
}
func TestSdkVersion(t *testing.T) {
- ctx := testJava(t, `
+ ctx, _ := testJava(t, `
java_library {
name: "foo",
srcs: ["a.java"],
@@ -313,7 +313,7 @@
}
func TestArchSpecific(t *testing.T) {
- ctx := testJava(t, `
+ ctx, _ := testJava(t, `
java_library {
name: "foo",
srcs: ["a.java"],
@@ -332,7 +332,7 @@
}
func TestBinary(t *testing.T) {
- ctx := testJava(t, `
+ ctx, _ := testJava(t, `
java_library_host {
name: "foo",
srcs: ["a.java"],
@@ -361,7 +361,7 @@
}
func TestPrebuilts(t *testing.T) {
- ctx := testJava(t, `
+ ctx, _ := testJava(t, `
java_library {
name: "foo",
srcs: ["a.java"],
@@ -412,7 +412,7 @@
}
func TestDefaults(t *testing.T) {
- ctx := testJava(t, `
+ ctx, _ := testJava(t, `
java_defaults {
name: "defaults",
srcs: ["a.java"],
@@ -558,7 +558,7 @@
for _, test := range table {
t.Run(test.name, func(t *testing.T) {
- ctx := testJava(t, `
+ ctx, _ := testJava(t, `
java_library {
name: "foo",
srcs: [
@@ -587,7 +587,7 @@
}
func TestIncludeSrcs(t *testing.T) {
- ctx := testJava(t, `
+ ctx, _ := testJava(t, `
java_library {
name: "foo",
srcs: [
@@ -650,7 +650,7 @@
}
func TestGeneratedSources(t *testing.T) {
- ctx := testJava(t, `
+ ctx, _ := testJava(t, `
java_library {
name: "foo",
srcs: [
@@ -683,7 +683,7 @@
}
func TestTurbine(t *testing.T) {
- ctx := testJava(t, `
+ ctx, _ := testJava(t, `
java_library {
name: "foo",
srcs: ["a.java"],
@@ -732,7 +732,7 @@
}
func TestSharding(t *testing.T) {
- ctx := testJava(t, `
+ ctx, _ := testJava(t, `
java_library {
name: "bar",
srcs: ["a.java","b.java","c.java"],
@@ -750,16 +750,22 @@
}
func TestDroiddoc(t *testing.T) {
- ctx := testJava(t, `
+ ctx, _ := testJava(t, `
droiddoc_template {
name: "droiddoc-templates-sdk",
path: ".",
}
+ filegroup {
+ name: "bar-doc-aidl-srcs",
+ srcs: ["bar-doc/IBar.aidl"],
+ path: "bar-doc",
+ }
droiddoc {
name: "bar-doc",
srcs: [
"bar-doc/*.java",
"bar-doc/IFoo.aidl",
+ ":bar-doc-aidl-srcs",
],
exclude_srcs: [
"bar-doc/b.java"
@@ -777,23 +783,24 @@
}
`)
- stubsJar := filepath.Join(buildDir, ".intermediates", "bar-doc", "android_common", "bar-doc-stubs.srcjar")
- barDoc := ctx.ModuleForTests("bar-doc", "android_common").Output("bar-doc-stubs.srcjar")
- if stubsJar != barDoc.Output.String() {
- t.Errorf("expected stubs Jar [%q], got %q", stubsJar, barDoc.Output.String())
- }
inputs := ctx.ModuleForTests("bar-doc", "android_common").Rule("javadoc").Inputs
var javaSrcs []string
for _, i := range inputs {
javaSrcs = append(javaSrcs, i.Base())
}
- if len(javaSrcs) != 2 || javaSrcs[0] != "a.java" || javaSrcs[1] != "IFoo.java" {
- t.Errorf("inputs of bar-doc must be []string{\"a.java\", \"IFoo.java\", but was %#v.", javaSrcs)
+ if len(javaSrcs) != 3 || javaSrcs[0] != "a.java" || javaSrcs[1] != "IFoo.java" || javaSrcs[2] != "IBar.java" {
+ t.Errorf("inputs of bar-doc must be []string{\"a.java\", \"IFoo.java\", \"IBar.java\", but was %#v.", javaSrcs)
+ }
+
+ aidlRule := ctx.ModuleForTests("bar-doc", "android_common").Output(inputs[2].String())
+ aidlFlags := aidlRule.Args["aidlFlags"]
+ if !strings.Contains(aidlFlags, "-Ibar-doc") {
+ t.Errorf("aidl flags for IBar.aidl should contain \"-Ibar-doc\", but was %q", aidlFlags)
}
}
func TestJarGenrules(t *testing.T) {
- ctx := testJava(t, `
+ ctx, _ := testJava(t, `
java_library {
name: "foo",
srcs: ["a.java"],
@@ -847,7 +854,7 @@
}
func TestExcludeFileGroupInSrcs(t *testing.T) {
- ctx := testJava(t, `
+ ctx, _ := testJava(t, `
java_library {
name: "foo",
srcs: ["a.java", ":foo-srcs"],
@@ -874,7 +881,7 @@
func TestJavaLibrary(t *testing.T) {
config := testConfig(nil)
- ctx := testContext(config, "", map[string][]byte{
+ ctx := testContext("", map[string][]byte{
"libcore/Android.bp": []byte(`
java_library {
name: "core",
@@ -886,7 +893,7 @@
}
func TestJavaSdkLibrary(t *testing.T) {
- ctx := testJava(t, `
+ ctx, _ := testJava(t, `
droiddoc_template {
name: "droiddoc-templates-sdk",
path: ".",
@@ -1057,7 +1064,7 @@
t.Run("Java language level 8", func(t *testing.T) {
// Test default javac -source 1.8 -target 1.8
- ctx := testJava(t, bp)
+ ctx, _ := testJava(t, bp)
checkPatchModuleFlag(t, ctx, "foo", "")
checkPatchModuleFlag(t, ctx, "bar", "")
@@ -1067,7 +1074,7 @@
t.Run("Java language level 9", func(t *testing.T) {
// Test again with javac -source 9 -target 9
config := testConfig(map[string]string{"EXPERIMENTAL_JAVA_LANGUAGE_LEVEL_9": "true"})
- ctx := testContext(config, bp, nil)
+ ctx := testContext(bp, nil)
run(t, ctx, config)
checkPatchModuleFlag(t, ctx, "foo", "")
diff --git a/java/kotlin_test.go b/java/kotlin_test.go
index e0eb0c0..5c6d45f 100644
--- a/java/kotlin_test.go
+++ b/java/kotlin_test.go
@@ -22,7 +22,7 @@
)
func TestKotlin(t *testing.T) {
- ctx := testJava(t, `
+ ctx, _ := testJava(t, `
java_library {
name: "foo",
srcs: ["a.java", "b.kt"],
@@ -84,7 +84,7 @@
}
func TestKapt(t *testing.T) {
- ctx := testJava(t, `
+ ctx, _ := testJava(t, `
java_library {
name: "foo",
srcs: ["a.java", "b.kt"],
diff --git a/java/plugin_test.go b/java/plugin_test.go
index d1aef2c..c7913d3 100644
--- a/java/plugin_test.go
+++ b/java/plugin_test.go
@@ -20,7 +20,7 @@
)
func TestNoPlugin(t *testing.T) {
- ctx := testJava(t, `
+ ctx, _ := testJava(t, `
java_library {
name: "foo",
srcs: ["a.java"],
@@ -44,7 +44,7 @@
}
func TestPlugin(t *testing.T) {
- ctx := testJava(t, `
+ ctx, _ := testJava(t, `
java_library {
name: "foo",
srcs: ["a.java"],
@@ -83,7 +83,7 @@
}
func TestPluginGeneratesApi(t *testing.T) {
- ctx := testJava(t, `
+ ctx, _ := testJava(t, `
java_library {
name: "foo",
srcs: ["a.java"],
diff --git a/java/proto.go b/java/proto.go
index 37de1d2..0ec6499 100644
--- a/java/proto.go
+++ b/java/proto.go
@@ -34,7 +34,7 @@
// 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 7b79a49..d1e2ae4 100644
--- a/java/sdk.go
+++ b/java/sdk.go
@@ -296,7 +296,7 @@
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/java/sdk_test.go b/java/sdk_test.go
index f82a4fb..6be17eb 100644
--- a/java/sdk_test.go
+++ b/java/sdk_test.go
@@ -282,7 +282,7 @@
if testcase.pdk {
config.TestProductVariables.Pdk = proptools.BoolPtr(true)
}
- ctx := testContext(config, bp, nil)
+ ctx := testContext(bp, nil)
run(t, ctx, config)
checkClasspath(t, ctx)
@@ -309,7 +309,7 @@
if testcase.pdk {
config.TestProductVariables.Pdk = proptools.BoolPtr(true)
}
- ctx := testContext(config, bp, nil)
+ ctx := testContext(bp, nil)
run(t, ctx, config)
javac := ctx.ModuleForTests("foo", variant).Rule("javac")
@@ -335,7 +335,7 @@
if testcase.pdk {
config.TestProductVariables.Pdk = proptools.BoolPtr(true)
}
- ctx := testContext(config, bp, nil)
+ ctx := testContext(bp, nil)
run(t, ctx, config)
checkClasspath(t, ctx)
diff --git a/java/support_libraries.go b/java/support_libraries.go
index 5a72f41..af7c3c2 100644
--- a/java/support_libraries.go
+++ b/java/support_libraries.go
@@ -52,8 +52,6 @@
supportAars = append(supportAars, name)
case *Library, *Import:
supportJars = append(supportJars, name)
- default:
- ctx.ModuleErrorf(module, "unknown module type %t", module)
}
})
diff --git a/python/proto.go b/python/proto.go
index 85ed1a5..b71e047 100644
--- a/python/proto.go
+++ b/python/proto.go
@@ -34,7 +34,7 @@
// 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 71c1d90..b468041 100644
--- a/scripts/jar-wrapper.sh
+++ b/scripts/jar-wrapper.sh
@@ -48,11 +48,11 @@
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} "$@"
diff --git a/scripts/strip.sh b/scripts/strip.sh
index bd62619..4a1ed3f 100755
--- a/scripts/strip.sh
+++ b/scripts/strip.sh
@@ -59,7 +59,7 @@
# ${CROSS_COMPILE}strip --strip-all does not strip .ARM.attributes,
# so we tell llvm-strip to keep it too.
if [ -z "${use_gnu_strip}" ]; then
- "${CLANG_BIN}/llvm-strip" --strip-all -keep-section=.ARM.attributes "${infile}" -o "${outfile}.tmp"
+ "${CLANG_BIN}/llvm-strip" --strip-all --keep-section=.ARM.attributes "${infile}" -o "${outfile}.tmp"
else
"${CROSS_COMPILE}strip" --strip-all "${infile}" -o "${outfile}.tmp"
fi
@@ -101,7 +101,7 @@
rm -f "${outfile}.dynsyms" "${outfile}.funcsyms" "${outfile}.keep_symbols" "${outfile}.debug" "${outfile}.mini_debuginfo" "${outfile}.mini_debuginfo.xz"
local fail=
if [ -z "${use_gnu_strip}" ]; then
- "${CLANG_BIN}/llvm-strip" --strip-all -keep-section=.ARM.attributes -remove-section=.comment "${infile}" -o "${outfile}.tmp" || fail=true
+ "${CLANG_BIN}/llvm-strip" --strip-all --keep-section=.ARM.attributes --remove-section=.comment "${infile}" -o "${outfile}.tmp" || fail=true
else
"${CROSS_COMPILE}strip" --strip-all -R .comment "${infile}" -o "${outfile}.tmp" || fail=true
fi
diff --git a/ui/build/config.go b/ui/build/config.go
index d1c84e8..bcb1965 100644
--- a/ui/build/config.go
+++ b/ui/build/config.go
@@ -61,6 +61,8 @@
const srcDirFileCheck = "build/soong/root.bp"
+var buildFiles = []string{"Android.mk", "Android.bp"}
+
type BuildAction uint
const (
@@ -305,12 +307,10 @@
if topDir == dir {
break
}
- // Find the build file from the directory where the build action was triggered by traversing up
- // the source tree. If a blank build filename is returned, simply use the directory where the build
- // action was invoked.
+
buildFile := findBuildFile(ctx, relDir)
if buildFile == "" {
- buildFile = filepath.Join(relDir, "Android.mk")
+ ctx.Fatalf("Build file not found for %s directory", relDir)
}
buildFiles = []string{buildFile}
targets = []string{convertToTarget(filepath.Dir(buildFile), targetNamePrefix)}
@@ -344,26 +344,57 @@
return targetNamePrefix + strings.ReplaceAll(dir, "/", "-")
}
-// findBuildFile finds a build file (makefile or blueprint file) by looking at dir first. If not
-// found, go up one level and repeat again until one is found and the path of that build file
-// relative to the root directory of the source tree is returned. The returned filename of build
-// file is "Android.mk". If one was not found, a blank string is returned.
+// hasBuildFile returns true if dir contains an Android build file.
+func hasBuildFile(ctx Context, dir string) bool {
+ for _, buildFile := range buildFiles {
+ _, err := os.Stat(filepath.Join(dir, buildFile))
+ if err == nil {
+ return true
+ }
+ if !os.IsNotExist(err) {
+ ctx.Fatalf("Error retrieving the build file stats: %v", err)
+ }
+ }
+ return false
+}
+
+// findBuildFile finds a build file (makefile or blueprint file) by looking if there is a build file
+// in the current and any sub directory of dir. If a build file is not found, traverse the path
+// up by one directory and repeat again until either a build file is found or reached to the root
+// source tree. The returned filename of build file is "Android.mk". If one was not found, a blank
+// string is returned.
func findBuildFile(ctx Context, dir string) string {
- // If the string is empty, assume it is top directory of the source tree.
- if dir == "" {
+ // If the string is empty or ".", assume it is top directory of the source tree.
+ if dir == "" || dir == "." {
return ""
}
- for ; dir != "."; dir = filepath.Dir(dir) {
- for _, buildFile := range []string{"Android.bp", "Android.mk"} {
- _, err := os.Stat(filepath.Join(dir, buildFile))
- if err == nil {
- // Returning the filename Android.mk as it might be used for ONE_SHOT_MAKEFILE variable.
- return filepath.Join(dir, "Android.mk")
+ found := false
+ for buildDir := dir; buildDir != "."; buildDir = filepath.Dir(buildDir) {
+ err := filepath.Walk(buildDir, func(path string, info os.FileInfo, err error) error {
+ if err != nil {
+ return err
}
- if !os.IsNotExist(err) {
- ctx.Fatalf("Error retrieving the build file stats: %v", err)
+ if found {
+ return filepath.SkipDir
}
+ if info.IsDir() {
+ return nil
+ }
+ for _, buildFile := range buildFiles {
+ if info.Name() == buildFile {
+ found = true
+ return filepath.SkipDir
+ }
+ }
+ return nil
+ })
+ if err != nil {
+ ctx.Fatalf("Error finding Android build file: %v", err)
+ }
+
+ if found {
+ return filepath.Join(buildDir, "Android.mk")
}
}
@@ -428,24 +459,23 @@
}
}
- buildFile := findBuildFile(ctx, dir)
- if buildFile == "" {
- ctx.Fatalf("Build file not found for %s directory", dir)
- }
- buildFileDir := filepath.Dir(buildFile)
-
- // If there are specified targets, find the build file in the directory. If dir does not
- // contain the build file, bail out as it is required for one shot build. If there are no
- // target specified, build all the modules in dir (or the closest one in the dir path).
+ // If there are specified targets to build in dir, an android build file must exist for the one
+ // shot build. For the non-targets case, find the appropriate build file and build all the
+ // modules in dir (or the closest one in the dir path).
if len(newTargets) > 0 {
- if buildFileDir != dir {
+ if !hasBuildFile(ctx, dir) {
ctx.Fatalf("Couldn't locate a build file from %s directory", dir)
}
+ buildFiles = append(buildFiles, filepath.Join(dir, "Android.mk"))
} else {
- newTargets = []string{convertToTarget(buildFileDir, targetNamePrefix)}
+ buildFile := findBuildFile(ctx, dir)
+ if buildFile == "" {
+ ctx.Fatalf("Build file not found for %s directory", dir)
+ }
+ newTargets = []string{convertToTarget(filepath.Dir(buildFile), targetNamePrefix)}
+ buildFiles = append(buildFiles, buildFile)
}
- buildFiles = append(buildFiles, buildFile)
targets = append(targets, newTargets...)
}
@@ -608,7 +638,7 @@
func (c *configImpl) OutDir() string {
if outDir, ok := c.environ.Get("OUT_DIR"); ok {
- return filepath.Clean(outDir)
+ return outDir
}
return "out"
}
diff --git a/ui/build/config_test.go b/ui/build/config_test.go
index 7a1ee17..463405a 100644
--- a/ui/build/config_test.go
+++ b/ui/build/config_test.go
@@ -441,7 +441,7 @@
buildFiles: []string{},
dirs: []string{"1/2/3:t1"},
curDir: "0",
- errStr: "Build file not found for 0/1/2/3 directory",
+ errStr: "Couldn't locate a build file from 0/1/2/3 directory",
}, {
description: "one target dir specified, one target specified, build file not in target dir",
dirsInTrees: []string{"0/1/2/3"},
@@ -545,8 +545,11 @@
// Array of build files to create in dir.
buildFiles []string
+ // Directories that exist in the source tree.
+ dirsInTrees []string
+
// ********* Action *********
- // Directory to create, also the base directory is where findBuildFile is invoked.
+ // The base directory is where findBuildFile is invoked.
dir string
// ********* Validation *********
@@ -555,38 +558,63 @@
}{{
description: "build file exists at leaf directory",
buildFiles: []string{"1/2/3/Android.bp"},
+ dirsInTrees: []string{"1/2/3"},
dir: "1/2/3",
expectedBuildFile: "1/2/3/Android.mk",
}, {
description: "build file exists in all directory paths",
buildFiles: []string{"1/Android.mk", "1/2/Android.mk", "1/2/3/Android.mk"},
+ dirsInTrees: []string{"1/2/3"},
dir: "1/2/3",
expectedBuildFile: "1/2/3/Android.mk",
}, {
description: "build file does not exist in all directory paths",
buildFiles: []string{},
+ dirsInTrees: []string{"1/2/3"},
dir: "1/2/3",
expectedBuildFile: "",
}, {
description: "build file exists only at top directory",
buildFiles: []string{"Android.bp"},
+ dirsInTrees: []string{"1/2/3"},
dir: "1/2/3",
expectedBuildFile: "",
}, {
description: "build file exist in a subdirectory",
buildFiles: []string{"1/2/Android.bp"},
+ dirsInTrees: []string{"1/2/3"},
dir: "1/2/3",
expectedBuildFile: "1/2/Android.mk",
}, {
description: "build file exists in a subdirectory",
buildFiles: []string{"1/Android.mk"},
+ dirsInTrees: []string{"1/2/3"},
dir: "1/2/3",
expectedBuildFile: "1/Android.mk",
}, {
description: "top directory",
buildFiles: []string{"Android.bp"},
+ dirsInTrees: []string{},
dir: ".",
expectedBuildFile: "",
+ }, {
+ description: "build file exists in subdirectory",
+ buildFiles: []string{"1/2/3/Android.bp", "1/2/4/Android.bp"},
+ dirsInTrees: []string{"1/2/3", "1/2/4"},
+ dir: "1/2",
+ expectedBuildFile: "1/2/Android.mk",
+ }, {
+ description: "build file exists in parent subdirectory",
+ buildFiles: []string{"1/5/Android.bp"},
+ dirsInTrees: []string{"1/2/3", "1/2/4", "1/5"},
+ dir: "1/2",
+ expectedBuildFile: "1/Android.mk",
+ }, {
+ description: "build file exists in deep parent's subdirectory.",
+ buildFiles: []string{"1/5/6/Android.bp"},
+ dirsInTrees: []string{"1/2/3", "1/2/4", "1/5/6", "1/5/7"},
+ dir: "1/2",
+ expectedBuildFile: "1/Android.mk",
}}
for _, tt := range tests {
@@ -601,10 +629,7 @@
}
defer os.RemoveAll(topDir)
- if tt.dir != "" {
- createDirectories(t, topDir, []string{tt.dir})
- }
-
+ createDirectories(t, topDir, tt.dirsInTrees)
createBuildFiles(t, topDir, tt.buildFiles)
curDir, err := os.Getwd()
@@ -709,11 +734,23 @@
// Expected environment variables to be set.
expectedEnvVars []envVar
+
+ // Expecting error from running test case.
+ expectedErrStr string
}
func testGetConfigArgs(t *testing.T, tt buildActionTestCase, action BuildAction, buildDependencies bool) {
ctx := testContext()
+ defer logger.Recover(func(err error) {
+ if tt.expectedErrStr == "" {
+ t.Fatalf("Got unexpected error: %v", err)
+ }
+ if tt.expectedErrStr != err.Error() {
+ t.Errorf("expected %s, got %s", tt.expectedErrStr, err.Error())
+ }
+ })
+
// Environment variables to set it to blank on every test case run.
resetEnvVars := []string{
"ONE_SHOT_MAKEFILE",
@@ -780,6 +817,11 @@
t.Errorf("expecting %s, got %s for environment variable %s", env.value, val, env.name)
}
}
+
+ // If the execution reached here and there was an expected error code, the unit test case failed.
+ if tt.expectedErrStr != "" {
+ t.Errorf("expecting error %s", tt.expectedErrStr)
+ }
}
func TestGetConfigArgsBuildModules(t *testing.T) {
@@ -875,6 +917,7 @@
envVar{
name: "ONE_SHOT_MAKEFILE",
value: "0/1/2/Android.mk"}},
+ expectedErrStr: "Build file not found for 0/1/2 directory",
}, {
description: "build action executed at root directory",
dirsInTrees: []string{},
@@ -978,7 +1021,7 @@
expectedArgs: []string{},
expectedEnvVars: []envVar{},
}, {
- description: "build file not found - no error is expected to return",
+ description: "build file not found",
dirsInTrees: []string{"0/1/2"},
buildFiles: []string{},
args: []string{},
@@ -986,6 +1029,7 @@
tidyOnly: "",
expectedArgs: []string{"MODULES-IN-0-1-2"},
expectedEnvVars: []envVar{},
+ expectedErrStr: "Build file not found for 0/1/2 directory",
}, {
description: "GET-INSTALL-PATH specified,",
dirsInTrees: []string{"0/1/2"},
diff --git a/ui/build/paths/config.go b/ui/build/paths/config.go
index a4be2ac..1a7412d 100644
--- a/ui/build/paths/config.go
+++ b/ui/build/paths/config.go
@@ -104,7 +104,6 @@
"realpath": Allowed,
"rsync": Allowed,
"sh": Allowed,
- "tar": Allowed,
"tr": Allowed,
"unzip": Allowed,
"zip": Allowed,
@@ -166,6 +165,7 @@
"sort": LinuxOnlyPrebuilt,
"stat": LinuxOnlyPrebuilt,
"tail": LinuxOnlyPrebuilt,
+ "tar": LinuxOnlyPrebuilt,
"tee": LinuxOnlyPrebuilt,
"timeout": LinuxOnlyPrebuilt,
"touch": LinuxOnlyPrebuilt,