Genrules that set uses_order_only_build_number_file: true will now have the ability to reference a $(build_number_file) label that will point to the build number file. It will also caused the build number file to be added as an order-only dependency, which will make it show up in the genrule sandbox. This is needed for converting make code that references the build number to soong, and for sandboxing the remaining unsandboxed genrules that reference the build number. Bug: 341873065 Test: m nothing --no-skip-soong-tests Change-Id: I9092cbb0eb39c5449a79f0ee40a4202262cef206
1338 lines
33 KiB
Go
1338 lines
33 KiB
Go
// Copyright 2018 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 genrule
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"regexp"
|
|
"strconv"
|
|
"strings"
|
|
"testing"
|
|
|
|
"android/soong/android"
|
|
|
|
"github.com/google/blueprint/proptools"
|
|
)
|
|
|
|
func TestMain(m *testing.M) {
|
|
os.Exit(m.Run())
|
|
}
|
|
|
|
var prepareForGenRuleTest = android.GroupFixturePreparers(
|
|
android.PrepareForTestWithArchMutator,
|
|
android.PrepareForTestWithDefaults,
|
|
android.PrepareForTestWithFilegroup,
|
|
PrepareForTestWithGenRuleBuildComponents,
|
|
android.FixtureRegisterWithContext(func(ctx android.RegistrationContext) {
|
|
android.RegisterPrebuiltMutators(ctx)
|
|
ctx.RegisterModuleType("tool", toolFactory)
|
|
ctx.RegisterModuleType("prebuilt_tool", prebuiltToolFactory)
|
|
ctx.RegisterModuleType("output", outputProducerFactory)
|
|
ctx.RegisterModuleType("use_source", useSourceFactory)
|
|
}),
|
|
android.FixtureMergeMockFs(android.MockFS{
|
|
"tool": nil,
|
|
"tool_file1": nil,
|
|
"tool_file2": nil,
|
|
"in1": nil,
|
|
"in2": nil,
|
|
"in1.txt": nil,
|
|
"in2.txt": nil,
|
|
"in3.txt": nil,
|
|
}),
|
|
)
|
|
|
|
func testGenruleBp() string {
|
|
return `
|
|
tool {
|
|
name: "tool",
|
|
}
|
|
|
|
filegroup {
|
|
name: "tool_files",
|
|
srcs: [
|
|
"tool_file1",
|
|
"tool_file2",
|
|
],
|
|
}
|
|
|
|
filegroup {
|
|
name: "1tool_file",
|
|
srcs: [
|
|
"tool_file1",
|
|
],
|
|
}
|
|
|
|
filegroup {
|
|
name: "ins",
|
|
srcs: [
|
|
"in1",
|
|
"in2",
|
|
],
|
|
}
|
|
|
|
filegroup {
|
|
name: "1in",
|
|
srcs: [
|
|
"in1",
|
|
],
|
|
}
|
|
|
|
filegroup {
|
|
name: "empty",
|
|
}
|
|
`
|
|
}
|
|
|
|
func TestGenruleCmd(t *testing.T) {
|
|
testcases := []struct {
|
|
name string
|
|
moduleName string
|
|
prop string
|
|
|
|
allowMissingDependencies bool
|
|
|
|
err string
|
|
expect string
|
|
}{
|
|
{
|
|
name: "empty location tool",
|
|
prop: `
|
|
tools: ["tool"],
|
|
out: ["out"],
|
|
cmd: "$(location) > $(out)",
|
|
`,
|
|
expect: "__SBOX_SANDBOX_DIR__/tools/out/bin/tool > __SBOX_SANDBOX_DIR__/out/out",
|
|
},
|
|
{
|
|
name: "empty location tool2",
|
|
prop: `
|
|
tools: [":tool"],
|
|
out: ["out"],
|
|
cmd: "$(location) > $(out)",
|
|
`,
|
|
expect: "__SBOX_SANDBOX_DIR__/tools/out/bin/tool > __SBOX_SANDBOX_DIR__/out/out",
|
|
},
|
|
{
|
|
name: "empty location tool file",
|
|
prop: `
|
|
tool_files: ["tool_file1"],
|
|
out: ["out"],
|
|
cmd: "$(location) > $(out)",
|
|
`,
|
|
expect: "__SBOX_SANDBOX_DIR__/tools/src/tool_file1 > __SBOX_SANDBOX_DIR__/out/out",
|
|
},
|
|
{
|
|
name: "empty location tool file fg",
|
|
prop: `
|
|
tool_files: [":1tool_file"],
|
|
out: ["out"],
|
|
cmd: "$(location) > $(out)",
|
|
`,
|
|
expect: "__SBOX_SANDBOX_DIR__/tools/src/tool_file1 > __SBOX_SANDBOX_DIR__/out/out",
|
|
},
|
|
{
|
|
name: "empty location tool and tool file",
|
|
prop: `
|
|
tools: ["tool"],
|
|
tool_files: ["tool_file1"],
|
|
out: ["out"],
|
|
cmd: "$(location) > $(out)",
|
|
`,
|
|
expect: "__SBOX_SANDBOX_DIR__/tools/out/bin/tool > __SBOX_SANDBOX_DIR__/out/out",
|
|
},
|
|
{
|
|
name: "tool",
|
|
prop: `
|
|
tools: ["tool"],
|
|
out: ["out"],
|
|
cmd: "$(location tool) > $(out)",
|
|
`,
|
|
expect: "__SBOX_SANDBOX_DIR__/tools/out/bin/tool > __SBOX_SANDBOX_DIR__/out/out",
|
|
},
|
|
{
|
|
name: "tool2",
|
|
prop: `
|
|
tools: [":tool"],
|
|
out: ["out"],
|
|
cmd: "$(location :tool) > $(out)",
|
|
`,
|
|
expect: "__SBOX_SANDBOX_DIR__/tools/out/bin/tool > __SBOX_SANDBOX_DIR__/out/out",
|
|
},
|
|
{
|
|
name: "tool file",
|
|
prop: `
|
|
tool_files: ["tool_file1"],
|
|
out: ["out"],
|
|
cmd: "$(location tool_file1) > $(out)",
|
|
`,
|
|
expect: "__SBOX_SANDBOX_DIR__/tools/src/tool_file1 > __SBOX_SANDBOX_DIR__/out/out",
|
|
},
|
|
{
|
|
name: "tool file fg",
|
|
prop: `
|
|
tool_files: [":1tool_file"],
|
|
out: ["out"],
|
|
cmd: "$(location :1tool_file) > $(out)",
|
|
`,
|
|
expect: "__SBOX_SANDBOX_DIR__/tools/src/tool_file1 > __SBOX_SANDBOX_DIR__/out/out",
|
|
},
|
|
{
|
|
name: "tool files",
|
|
prop: `
|
|
tool_files: [":tool_files"],
|
|
out: ["out"],
|
|
cmd: "$(locations :tool_files) > $(out)",
|
|
`,
|
|
expect: "__SBOX_SANDBOX_DIR__/tools/src/tool_file1 __SBOX_SANDBOX_DIR__/tools/src/tool_file2 > __SBOX_SANDBOX_DIR__/out/out",
|
|
},
|
|
{
|
|
name: "in1",
|
|
prop: `
|
|
srcs: ["in1"],
|
|
out: ["out"],
|
|
cmd: "cat $(in) > $(out)",
|
|
`,
|
|
expect: "cat in1 > __SBOX_SANDBOX_DIR__/out/out",
|
|
},
|
|
{
|
|
name: "in1 fg",
|
|
prop: `
|
|
srcs: [":1in"],
|
|
out: ["out"],
|
|
cmd: "cat $(in) > $(out)",
|
|
`,
|
|
expect: "cat in1 > __SBOX_SANDBOX_DIR__/out/out",
|
|
},
|
|
{
|
|
name: "ins",
|
|
prop: `
|
|
srcs: ["in1", "in2"],
|
|
out: ["out"],
|
|
cmd: "cat $(in) > $(out)",
|
|
`,
|
|
expect: "cat in1 in2 > __SBOX_SANDBOX_DIR__/out/out",
|
|
},
|
|
{
|
|
name: "ins fg",
|
|
prop: `
|
|
srcs: [":ins"],
|
|
out: ["out"],
|
|
cmd: "cat $(in) > $(out)",
|
|
`,
|
|
expect: "cat in1 in2 > __SBOX_SANDBOX_DIR__/out/out",
|
|
},
|
|
{
|
|
name: "location in1",
|
|
prop: `
|
|
srcs: ["in1"],
|
|
out: ["out"],
|
|
cmd: "cat $(location in1) > $(out)",
|
|
`,
|
|
expect: "cat in1 > __SBOX_SANDBOX_DIR__/out/out",
|
|
},
|
|
{
|
|
name: "location in1 fg",
|
|
prop: `
|
|
srcs: [":1in"],
|
|
out: ["out"],
|
|
cmd: "cat $(location :1in) > $(out)",
|
|
`,
|
|
expect: "cat in1 > __SBOX_SANDBOX_DIR__/out/out",
|
|
},
|
|
{
|
|
name: "location ins",
|
|
prop: `
|
|
srcs: ["in1", "in2"],
|
|
out: ["out"],
|
|
cmd: "cat $(location in1) > $(out)",
|
|
`,
|
|
expect: "cat in1 > __SBOX_SANDBOX_DIR__/out/out",
|
|
},
|
|
{
|
|
name: "location ins fg",
|
|
prop: `
|
|
srcs: [":ins"],
|
|
out: ["out"],
|
|
cmd: "cat $(locations :ins) > $(out)",
|
|
`,
|
|
expect: "cat in1 in2 > __SBOX_SANDBOX_DIR__/out/out",
|
|
},
|
|
{
|
|
name: "outs",
|
|
prop: `
|
|
out: ["out", "out2"],
|
|
cmd: "echo foo > $(out)",
|
|
`,
|
|
expect: "echo foo > __SBOX_SANDBOX_DIR__/out/out __SBOX_SANDBOX_DIR__/out/out2",
|
|
},
|
|
{
|
|
name: "location out",
|
|
prop: `
|
|
out: ["out", "out2"],
|
|
cmd: "echo foo > $(location out2)",
|
|
`,
|
|
expect: "echo foo > __SBOX_SANDBOX_DIR__/out/out2",
|
|
},
|
|
{
|
|
name: "gendir",
|
|
prop: `
|
|
out: ["out"],
|
|
cmd: "echo foo > $(genDir)/foo && cp $(genDir)/foo $(out)",
|
|
`,
|
|
expect: "echo foo > __SBOX_SANDBOX_DIR__/out/foo && cp __SBOX_SANDBOX_DIR__/out/foo __SBOX_SANDBOX_DIR__/out/out",
|
|
},
|
|
{
|
|
name: "$",
|
|
prop: `
|
|
out: ["out"],
|
|
cmd: "echo $$ > $(out)",
|
|
`,
|
|
expect: "echo $ > __SBOX_SANDBOX_DIR__/out/out",
|
|
},
|
|
|
|
{
|
|
name: "error empty location",
|
|
prop: `
|
|
out: ["out"],
|
|
cmd: "$(location) > $(out)",
|
|
`,
|
|
err: "at least one `tools` or `tool_files` is required if $(location) is used",
|
|
},
|
|
{
|
|
name: "error empty location no files",
|
|
prop: `
|
|
tool_files: [":empty"],
|
|
out: ["out"],
|
|
cmd: "$(location) > $(out)",
|
|
`,
|
|
err: `default label ":empty" has no files`,
|
|
},
|
|
{
|
|
name: "error empty location multiple files",
|
|
prop: `
|
|
tool_files: [":tool_files"],
|
|
out: ["out"],
|
|
cmd: "$(location) > $(out)",
|
|
`,
|
|
err: `default label ":tool_files" has multiple files`,
|
|
},
|
|
{
|
|
name: "error location",
|
|
prop: `
|
|
out: ["out"],
|
|
cmd: "echo foo > $(location missing)",
|
|
`,
|
|
err: `unknown location label "missing" is not in srcs, out, tools or tool_files.`,
|
|
},
|
|
{
|
|
name: "error locations",
|
|
prop: `
|
|
out: ["out"],
|
|
cmd: "echo foo > $(locations missing)",
|
|
`,
|
|
err: `unknown locations label "missing" is not in srcs, out, tools or tool_files`,
|
|
},
|
|
{
|
|
name: "error location no files",
|
|
prop: `
|
|
out: ["out"],
|
|
srcs: [":empty"],
|
|
cmd: "echo $(location :empty) > $(out)",
|
|
`,
|
|
err: `label ":empty" has no files`,
|
|
},
|
|
{
|
|
name: "error locations no files",
|
|
prop: `
|
|
out: ["out"],
|
|
srcs: [":empty"],
|
|
cmd: "echo $(locations :empty) > $(out)",
|
|
`,
|
|
err: `label ":empty" has no files`,
|
|
},
|
|
{
|
|
name: "error location multiple files",
|
|
prop: `
|
|
out: ["out"],
|
|
srcs: [":ins"],
|
|
cmd: "echo $(location :ins) > $(out)",
|
|
`,
|
|
err: `label ":ins" has multiple files`,
|
|
},
|
|
{
|
|
name: "error variable",
|
|
prop: `
|
|
out: ["out"],
|
|
srcs: ["in1"],
|
|
cmd: "echo $(foo) > $(out)",
|
|
`,
|
|
err: `unknown variable '$(foo)'`,
|
|
},
|
|
{
|
|
name: "error no out",
|
|
prop: `
|
|
cmd: "echo foo > $(out)",
|
|
`,
|
|
err: "must have at least one output file",
|
|
},
|
|
{
|
|
name: "srcs allow missing dependencies",
|
|
prop: `
|
|
srcs: [":missing"],
|
|
out: ["out"],
|
|
cmd: "cat $(location :missing) > $(out)",
|
|
`,
|
|
|
|
allowMissingDependencies: true,
|
|
|
|
expect: "cat '***missing srcs :missing***' > __SBOX_SANDBOX_DIR__/out/out",
|
|
},
|
|
{
|
|
name: "tool allow missing dependencies",
|
|
prop: `
|
|
tools: [":missing"],
|
|
out: ["out"],
|
|
cmd: "$(location :missing) > $(out)",
|
|
`,
|
|
|
|
allowMissingDependencies: true,
|
|
|
|
expect: "'***missing tool :missing***' > __SBOX_SANDBOX_DIR__/out/out",
|
|
},
|
|
}
|
|
|
|
for _, test := range testcases {
|
|
t.Run(test.name, func(t *testing.T) {
|
|
moduleName := "gen"
|
|
if test.moduleName != "" {
|
|
moduleName = test.moduleName
|
|
}
|
|
bp := fmt.Sprintf(`
|
|
genrule {
|
|
name: "%s",
|
|
%s
|
|
}`, moduleName, test.prop)
|
|
var expectedErrors []string
|
|
if test.err != "" {
|
|
expectedErrors = append(expectedErrors, regexp.QuoteMeta(test.err))
|
|
}
|
|
|
|
result := android.GroupFixturePreparers(
|
|
prepareForGenRuleTest,
|
|
android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
|
|
variables.Allow_missing_dependencies = proptools.BoolPtr(test.allowMissingDependencies)
|
|
}),
|
|
android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
|
|
variables.GenruleSandboxing = proptools.BoolPtr(true)
|
|
}),
|
|
android.FixtureModifyContext(func(ctx *android.TestContext) {
|
|
ctx.SetAllowMissingDependencies(test.allowMissingDependencies)
|
|
}),
|
|
).
|
|
ExtendWithErrorHandler(android.FixtureExpectsAllErrorsToMatchAPattern(expectedErrors)).
|
|
RunTestWithBp(t, testGenruleBp()+bp)
|
|
|
|
if expectedErrors != nil {
|
|
return
|
|
}
|
|
|
|
gen := result.Module(moduleName, "").(*Module)
|
|
android.AssertStringEquals(t, "raw commands", test.expect, gen.rawCommands[0])
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestGenruleHashInputs(t *testing.T) {
|
|
|
|
// The basic idea here is to verify that the sbox command (which is
|
|
// in the Command field of the generate rule) contains a hash of the
|
|
// inputs, but only if $(in) is not referenced in the genrule cmd
|
|
// property.
|
|
|
|
// By including a hash of the inputs, we cause the rule to re-run if
|
|
// the list of inputs changes (because the sbox command changes).
|
|
|
|
// However, if the genrule cmd property already contains $(in), then
|
|
// the dependency is already expressed, so we don't need to include the
|
|
// hash in that case.
|
|
|
|
bp := `
|
|
genrule {
|
|
name: "hash0",
|
|
srcs: ["in1.txt", "in2.txt"],
|
|
out: ["out"],
|
|
cmd: "echo foo > $(out)",
|
|
}
|
|
genrule {
|
|
name: "hash1",
|
|
srcs: ["*.txt"],
|
|
out: ["out"],
|
|
cmd: "echo bar > $(out)",
|
|
}
|
|
genrule {
|
|
name: "hash2",
|
|
srcs: ["*.txt"],
|
|
out: ["out"],
|
|
cmd: "echo $(in) > $(out)",
|
|
}
|
|
`
|
|
testcases := []struct {
|
|
name string
|
|
expectedHash string
|
|
}{
|
|
{
|
|
name: "hash0",
|
|
// sha256 value obtained from: echo -en 'in1.txt\nin2.txt' | sha256sum
|
|
expectedHash: "18da75b9b1cc74b09e365b4ca2e321b5d618f438cc632b387ad9dc2ab4b20e9d",
|
|
},
|
|
{
|
|
name: "hash1",
|
|
// sha256 value obtained from: echo -en 'in1.txt\nin2.txt\nin3.txt' | sha256sum
|
|
expectedHash: "a38d432a4b19df93140e1f1fe26c97ff0387dae01fe506412b47208f0595fb45",
|
|
},
|
|
{
|
|
name: "hash2",
|
|
// sha256 value obtained from: echo -en 'in1.txt\nin2.txt\nin3.txt' | sha256sum
|
|
expectedHash: "a38d432a4b19df93140e1f1fe26c97ff0387dae01fe506412b47208f0595fb45",
|
|
},
|
|
}
|
|
|
|
result := prepareForGenRuleTest.RunTestWithBp(t, testGenruleBp()+bp)
|
|
|
|
for _, test := range testcases {
|
|
t.Run(test.name, func(t *testing.T) {
|
|
gen := result.ModuleForTests(test.name, "")
|
|
manifest := android.RuleBuilderSboxProtoForTests(t, result.TestContext, gen.Output("genrule.sbox.textproto"))
|
|
hash := manifest.Commands[0].GetInputHash()
|
|
|
|
android.AssertStringEquals(t, "hash", test.expectedHash, hash)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestGenSrcs(t *testing.T) {
|
|
testcases := []struct {
|
|
name string
|
|
prop string
|
|
|
|
allowMissingDependencies bool
|
|
|
|
err string
|
|
cmds []string
|
|
deps []string
|
|
files []string
|
|
shards int
|
|
inputs []string
|
|
}{
|
|
{
|
|
name: "gensrcs",
|
|
prop: `
|
|
tools: ["tool"],
|
|
srcs: ["in1.txt", "in2.txt"],
|
|
cmd: "$(location) $(in) > $(out)",
|
|
`,
|
|
cmds: []string{
|
|
"bash -c '__SBOX_SANDBOX_DIR__/tools/out/bin/tool in1.txt > __SBOX_SANDBOX_DIR__/out/in1.h' && bash -c '__SBOX_SANDBOX_DIR__/tools/out/bin/tool in2.txt > __SBOX_SANDBOX_DIR__/out/in2.h'",
|
|
},
|
|
deps: []string{
|
|
"out/soong/.intermediates/gen/gen/gensrcs/in1.h",
|
|
"out/soong/.intermediates/gen/gen/gensrcs/in2.h",
|
|
},
|
|
files: []string{
|
|
"out/soong/.intermediates/gen/gen/gensrcs/in1.h",
|
|
"out/soong/.intermediates/gen/gen/gensrcs/in2.h",
|
|
},
|
|
},
|
|
{
|
|
name: "shards",
|
|
prop: `
|
|
tools: ["tool"],
|
|
srcs: ["in1.txt", "in2.txt", "in3.txt"],
|
|
cmd: "$(location) $(in) > $(out)",
|
|
shard_size: 2,
|
|
`,
|
|
cmds: []string{
|
|
"bash -c '__SBOX_SANDBOX_DIR__/tools/out/bin/tool in1.txt > __SBOX_SANDBOX_DIR__/out/in1.h' && bash -c '__SBOX_SANDBOX_DIR__/tools/out/bin/tool in2.txt > __SBOX_SANDBOX_DIR__/out/in2.h'",
|
|
"bash -c '__SBOX_SANDBOX_DIR__/tools/out/bin/tool in3.txt > __SBOX_SANDBOX_DIR__/out/in3.h'",
|
|
},
|
|
deps: []string{
|
|
"out/soong/.intermediates/gen/gen/gensrcs/in1.h",
|
|
"out/soong/.intermediates/gen/gen/gensrcs/in2.h",
|
|
"out/soong/.intermediates/gen/gen/gensrcs/in3.h",
|
|
},
|
|
files: []string{
|
|
"out/soong/.intermediates/gen/gen/gensrcs/in1.h",
|
|
"out/soong/.intermediates/gen/gen/gensrcs/in2.h",
|
|
"out/soong/.intermediates/gen/gen/gensrcs/in3.h",
|
|
},
|
|
},
|
|
{
|
|
name: "data",
|
|
prop: `
|
|
tools: ["tool"],
|
|
srcs: ["in1.txt", "in2.txt", "in3.txt"],
|
|
cmd: "$(location) $(in) --extra_input=$(location baz.txt) > $(out)",
|
|
data: ["baz.txt"],
|
|
shard_size: 2,
|
|
`,
|
|
cmds: []string{
|
|
"bash -c '__SBOX_SANDBOX_DIR__/tools/out/bin/tool in1.txt --extra_input=baz.txt > __SBOX_SANDBOX_DIR__/out/in1.h' && bash -c '__SBOX_SANDBOX_DIR__/tools/out/bin/tool in2.txt --extra_input=baz.txt > __SBOX_SANDBOX_DIR__/out/in2.h'",
|
|
"bash -c '__SBOX_SANDBOX_DIR__/tools/out/bin/tool in3.txt --extra_input=baz.txt > __SBOX_SANDBOX_DIR__/out/in3.h'",
|
|
},
|
|
deps: []string{
|
|
"out/soong/.intermediates/gen/gen/gensrcs/in1.h",
|
|
"out/soong/.intermediates/gen/gen/gensrcs/in2.h",
|
|
"out/soong/.intermediates/gen/gen/gensrcs/in3.h",
|
|
},
|
|
files: []string{
|
|
"out/soong/.intermediates/gen/gen/gensrcs/in1.h",
|
|
"out/soong/.intermediates/gen/gen/gensrcs/in2.h",
|
|
"out/soong/.intermediates/gen/gen/gensrcs/in3.h",
|
|
},
|
|
shards: 2,
|
|
inputs: []string{
|
|
"baz.txt",
|
|
},
|
|
},
|
|
}
|
|
|
|
checkInputs := func(t *testing.T, rule android.TestingBuildParams, inputs []string) {
|
|
t.Helper()
|
|
if len(inputs) == 0 {
|
|
return
|
|
}
|
|
inputBaseNames := map[string]bool{}
|
|
for _, f := range rule.Implicits {
|
|
inputBaseNames[f.Base()] = true
|
|
}
|
|
for _, f := range inputs {
|
|
if _, ok := inputBaseNames[f]; !ok {
|
|
t.Errorf("Expected to find input file %q for %q, but did not", f, rule.Description)
|
|
}
|
|
}
|
|
}
|
|
|
|
for _, test := range testcases {
|
|
t.Run(test.name, func(t *testing.T) {
|
|
bp := "gensrcs {\n"
|
|
bp += `name: "gen",` + "\n"
|
|
bp += `output_extension: "h",` + "\n"
|
|
bp += test.prop
|
|
bp += "}\n"
|
|
|
|
var expectedErrors []string
|
|
if test.err != "" {
|
|
expectedErrors = append(expectedErrors, regexp.QuoteMeta(test.err))
|
|
}
|
|
|
|
result := prepareForGenRuleTest.
|
|
ExtendWithErrorHandler(android.FixtureExpectsAllErrorsToMatchAPattern(expectedErrors)).
|
|
RunTestWithBp(t, testGenruleBp()+bp)
|
|
|
|
mod := result.ModuleForTests("gen", "")
|
|
if expectedErrors != nil {
|
|
return
|
|
}
|
|
|
|
if test.shards > 0 {
|
|
for i := 0; i < test.shards; i++ {
|
|
r := mod.Rule("generator" + strconv.Itoa(i))
|
|
checkInputs(t, r, test.inputs)
|
|
}
|
|
} else {
|
|
r := mod.Rule("generator")
|
|
checkInputs(t, r, test.inputs)
|
|
}
|
|
|
|
gen := result.Module("gen", "").(*Module)
|
|
android.AssertDeepEquals(t, "cmd", test.cmds, gen.rawCommands)
|
|
|
|
android.AssertPathsRelativeToTopEquals(t, "deps", test.deps, gen.outputDeps)
|
|
|
|
android.AssertPathsRelativeToTopEquals(t, "files", test.files, gen.outputFiles)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestGenruleDefaults(t *testing.T) {
|
|
bp := `
|
|
genrule_defaults {
|
|
name: "gen_defaults1",
|
|
cmd: "cp $(in) $(out)",
|
|
}
|
|
|
|
genrule_defaults {
|
|
name: "gen_defaults2",
|
|
srcs: ["in1"],
|
|
}
|
|
|
|
genrule {
|
|
name: "gen",
|
|
out: ["out"],
|
|
defaults: ["gen_defaults1", "gen_defaults2"],
|
|
}
|
|
`
|
|
|
|
result := prepareForGenRuleTest.RunTestWithBp(t, testGenruleBp()+bp)
|
|
|
|
gen := result.Module("gen", "").(*Module)
|
|
|
|
expectedCmd := "cp in1 __SBOX_SANDBOX_DIR__/out/out"
|
|
android.AssertStringEquals(t, "cmd", expectedCmd, gen.rawCommands[0])
|
|
|
|
expectedSrcs := []string{"in1"}
|
|
android.AssertDeepEquals(t, "srcs", expectedSrcs, gen.properties.ResolvedSrcs)
|
|
}
|
|
|
|
func TestGenruleAllowMissingDependencies(t *testing.T) {
|
|
bp := `
|
|
output {
|
|
name: "disabled",
|
|
enabled: false,
|
|
}
|
|
|
|
genrule {
|
|
name: "gen",
|
|
srcs: [
|
|
":disabled",
|
|
],
|
|
out: ["out"],
|
|
cmd: "cat $(in) > $(out)",
|
|
}
|
|
`
|
|
result := android.GroupFixturePreparers(
|
|
prepareForGenRuleTest,
|
|
android.FixtureModifyConfigAndContext(
|
|
func(config android.Config, ctx *android.TestContext) {
|
|
config.TestProductVariables.Allow_missing_dependencies = proptools.BoolPtr(true)
|
|
ctx.SetAllowMissingDependencies(true)
|
|
})).RunTestWithBp(t, bp)
|
|
|
|
gen := result.ModuleForTests("gen", "").Output("out")
|
|
if gen.Rule != android.ErrorRule {
|
|
t.Errorf("Expected missing dependency error rule for gen, got %q", gen.Rule.String())
|
|
}
|
|
}
|
|
|
|
func TestGenruleOutputFiles(t *testing.T) {
|
|
bp := `
|
|
genrule {
|
|
name: "gen",
|
|
out: ["foo", "sub/bar"],
|
|
cmd: "echo foo > $(location foo) && echo bar > $(location sub/bar)",
|
|
}
|
|
use_source {
|
|
name: "gen_foo",
|
|
srcs: [":gen{foo}"],
|
|
}
|
|
use_source {
|
|
name: "gen_bar",
|
|
srcs: [":gen{sub/bar}"],
|
|
}
|
|
use_source {
|
|
name: "gen_all",
|
|
srcs: [":gen"],
|
|
}
|
|
`
|
|
|
|
result := prepareForGenRuleTest.RunTestWithBp(t, testGenruleBp()+bp)
|
|
android.AssertPathsRelativeToTopEquals(t,
|
|
"genrule.tag with output",
|
|
[]string{"out/soong/.intermediates/gen/gen/foo"},
|
|
result.ModuleForTests("gen_foo", "").Module().(*useSource).srcs)
|
|
android.AssertPathsRelativeToTopEquals(t,
|
|
"genrule.tag with output in subdir",
|
|
[]string{"out/soong/.intermediates/gen/gen/sub/bar"},
|
|
result.ModuleForTests("gen_bar", "").Module().(*useSource).srcs)
|
|
android.AssertPathsRelativeToTopEquals(t,
|
|
"genrule.tag with all",
|
|
[]string{"out/soong/.intermediates/gen/gen/foo", "out/soong/.intermediates/gen/gen/sub/bar"},
|
|
result.ModuleForTests("gen_all", "").Module().(*useSource).srcs)
|
|
}
|
|
|
|
func TestGenruleInterface(t *testing.T) {
|
|
result := android.GroupFixturePreparers(
|
|
prepareForGenRuleTest,
|
|
android.FixtureMergeMockFs(android.MockFS{
|
|
"package-dir/Android.bp": []byte(`
|
|
genrule {
|
|
name: "module-name",
|
|
cmd: "mkdir -p $(genDir) && cat $(in) >> $(genDir)/$(out)",
|
|
srcs: [
|
|
"src/foo.proto",
|
|
],
|
|
out: ["proto.h", "bar/proto.h"],
|
|
export_include_dirs: [".", "bar"],
|
|
}
|
|
`),
|
|
}),
|
|
).RunTest(t)
|
|
|
|
exportedIncludeDirs := []string{
|
|
"out/soong/.intermediates/package-dir/module-name/gen/package-dir",
|
|
"out/soong/.intermediates/package-dir/module-name/gen",
|
|
"out/soong/.intermediates/package-dir/module-name/gen/package-dir/bar",
|
|
"out/soong/.intermediates/package-dir/module-name/gen/bar",
|
|
}
|
|
gen := result.Module("module-name", "").(*Module)
|
|
|
|
android.AssertPathsRelativeToTopEquals(
|
|
t,
|
|
"include path",
|
|
exportedIncludeDirs,
|
|
gen.GeneratedHeaderDirs(),
|
|
)
|
|
android.AssertPathsRelativeToTopEquals(
|
|
t,
|
|
"files",
|
|
[]string{
|
|
"out/soong/.intermediates/package-dir/module-name/gen/proto.h",
|
|
"out/soong/.intermediates/package-dir/module-name/gen/bar/proto.h",
|
|
},
|
|
gen.GeneratedSourceFiles(),
|
|
)
|
|
}
|
|
|
|
func TestGenSrcsWithNonRootAndroidBpOutputFiles(t *testing.T) {
|
|
result := android.GroupFixturePreparers(
|
|
prepareForGenRuleTest,
|
|
android.FixtureMergeMockFs(android.MockFS{
|
|
"external-protos/path/Android.bp": []byte(`
|
|
filegroup {
|
|
name: "external-protos",
|
|
srcs: ["baz/baz.proto", "bar.proto"],
|
|
}
|
|
`),
|
|
"package-dir/Android.bp": []byte(`
|
|
gensrcs {
|
|
name: "module-name",
|
|
cmd: "mkdir -p $(genDir) && cat $(in) >> $(genDir)/$(out)",
|
|
srcs: [
|
|
"src/foo.proto",
|
|
":external-protos",
|
|
],
|
|
output_extension: "proto.h",
|
|
}
|
|
`),
|
|
}),
|
|
).RunTest(t)
|
|
|
|
exportedIncludeDir := "out/soong/.intermediates/package-dir/module-name/gen/gensrcs"
|
|
gen := result.Module("module-name", "").(*Module)
|
|
|
|
android.AssertPathsRelativeToTopEquals(
|
|
t,
|
|
"include path",
|
|
[]string{exportedIncludeDir},
|
|
gen.exportedIncludeDirs,
|
|
)
|
|
android.AssertPathsRelativeToTopEquals(
|
|
t,
|
|
"files",
|
|
[]string{
|
|
exportedIncludeDir + "/package-dir/src/foo.proto.h",
|
|
exportedIncludeDir + "/external-protos/path/baz/baz.proto.h",
|
|
exportedIncludeDir + "/external-protos/path/bar.proto.h",
|
|
},
|
|
gen.outputFiles,
|
|
)
|
|
}
|
|
|
|
func TestGenSrcsWithSrcsFromExternalPackage(t *testing.T) {
|
|
bp := `
|
|
gensrcs {
|
|
name: "module-name",
|
|
cmd: "mkdir -p $(genDir) && cat $(in) >> $(genDir)/$(out)",
|
|
srcs: [
|
|
":external-protos",
|
|
],
|
|
output_extension: "proto.h",
|
|
}
|
|
`
|
|
result := android.GroupFixturePreparers(
|
|
prepareForGenRuleTest,
|
|
android.FixtureMergeMockFs(android.MockFS{
|
|
"external-protos/path/Android.bp": []byte(`
|
|
filegroup {
|
|
name: "external-protos",
|
|
srcs: ["foo/foo.proto", "bar.proto"],
|
|
}
|
|
`),
|
|
}),
|
|
).RunTestWithBp(t, bp)
|
|
|
|
exportedIncludeDir := "out/soong/.intermediates/module-name/gen/gensrcs"
|
|
gen := result.Module("module-name", "").(*Module)
|
|
|
|
android.AssertPathsRelativeToTopEquals(
|
|
t,
|
|
"include path",
|
|
[]string{exportedIncludeDir},
|
|
gen.exportedIncludeDirs,
|
|
)
|
|
android.AssertPathsRelativeToTopEquals(
|
|
t,
|
|
"files",
|
|
[]string{
|
|
exportedIncludeDir + "/external-protos/path/foo/foo.proto.h",
|
|
exportedIncludeDir + "/external-protos/path/bar.proto.h",
|
|
},
|
|
gen.outputFiles,
|
|
)
|
|
}
|
|
|
|
func TestGenSrcsWithTrimExtAndOutpuExtension(t *testing.T) {
|
|
result := android.GroupFixturePreparers(
|
|
prepareForGenRuleTest,
|
|
android.FixtureMergeMockFs(android.MockFS{
|
|
"external-protos/path/Android.bp": []byte(`
|
|
filegroup {
|
|
name: "external-protos",
|
|
srcs: [
|
|
"baz.a.b.c.proto/baz.a.b.c.proto",
|
|
"bar.a.b.c.proto",
|
|
"qux.ext.a.b.c.proto",
|
|
],
|
|
}
|
|
`),
|
|
"package-dir/Android.bp": []byte(`
|
|
gensrcs {
|
|
name: "module-name",
|
|
cmd: "mkdir -p $(genDir) && cat $(in) >> $(genDir)/$(out)",
|
|
srcs: [
|
|
"src/foo.a.b.c.proto",
|
|
":external-protos",
|
|
],
|
|
|
|
trim_extension: ".a.b.c.proto",
|
|
output_extension: "proto.h",
|
|
}
|
|
`),
|
|
}),
|
|
).RunTest(t)
|
|
|
|
exportedIncludeDir := "out/soong/.intermediates/package-dir/module-name/gen/gensrcs"
|
|
gen := result.Module("module-name", "").(*Module)
|
|
|
|
android.AssertPathsRelativeToTopEquals(
|
|
t,
|
|
"include path",
|
|
[]string{exportedIncludeDir},
|
|
gen.exportedIncludeDirs,
|
|
)
|
|
android.AssertPathsRelativeToTopEquals(
|
|
t,
|
|
"files",
|
|
[]string{
|
|
exportedIncludeDir + "/package-dir/src/foo.proto.h",
|
|
exportedIncludeDir + "/external-protos/path/baz.a.b.c.proto/baz.proto.h",
|
|
exportedIncludeDir + "/external-protos/path/bar.proto.h",
|
|
exportedIncludeDir + "/external-protos/path/qux.ext.proto.h",
|
|
},
|
|
gen.outputFiles,
|
|
)
|
|
}
|
|
|
|
func TestGenSrcsWithTrimExtButNoOutpuExtension(t *testing.T) {
|
|
result := android.GroupFixturePreparers(
|
|
prepareForGenRuleTest,
|
|
android.FixtureMergeMockFs(android.MockFS{
|
|
"external-protos/path/Android.bp": []byte(`
|
|
filegroup {
|
|
name: "external-protos",
|
|
srcs: [
|
|
"baz.a.b.c.proto/baz.a.b.c.proto",
|
|
"bar.a.b.c.proto",
|
|
"qux.ext.a.b.c.proto",
|
|
],
|
|
}
|
|
`),
|
|
"package-dir/Android.bp": []byte(`
|
|
gensrcs {
|
|
name: "module-name",
|
|
cmd: "mkdir -p $(genDir) && cat $(in) >> $(genDir)/$(out)",
|
|
srcs: [
|
|
"src/foo.a.b.c.proto",
|
|
":external-protos",
|
|
],
|
|
|
|
trim_extension: ".a.b.c.proto",
|
|
}
|
|
`),
|
|
}),
|
|
).RunTest(t)
|
|
|
|
exportedIncludeDir := "out/soong/.intermediates/package-dir/module-name/gen/gensrcs"
|
|
gen := result.Module("module-name", "").(*Module)
|
|
|
|
android.AssertPathsRelativeToTopEquals(
|
|
t,
|
|
"include path",
|
|
[]string{exportedIncludeDir},
|
|
gen.exportedIncludeDirs,
|
|
)
|
|
android.AssertPathsRelativeToTopEquals(
|
|
t,
|
|
"files",
|
|
[]string{
|
|
exportedIncludeDir + "/package-dir/src/foo",
|
|
exportedIncludeDir + "/external-protos/path/baz.a.b.c.proto/baz",
|
|
exportedIncludeDir + "/external-protos/path/bar",
|
|
exportedIncludeDir + "/external-protos/path/qux.ext",
|
|
},
|
|
gen.outputFiles,
|
|
)
|
|
}
|
|
|
|
func TestGenSrcsWithOutpuExtension(t *testing.T) {
|
|
result := android.GroupFixturePreparers(
|
|
prepareForGenRuleTest,
|
|
android.FixtureMergeMockFs(android.MockFS{
|
|
"external-protos/path/Android.bp": []byte(`
|
|
filegroup {
|
|
name: "external-protos",
|
|
srcs: ["baz/baz.a.b.c.proto", "bar.a.b.c.proto"],
|
|
}
|
|
`),
|
|
"package-dir/Android.bp": []byte(`
|
|
gensrcs {
|
|
name: "module-name",
|
|
cmd: "mkdir -p $(genDir) && cat $(in) >> $(genDir)/$(out)",
|
|
srcs: [
|
|
"src/foo.a.b.c.proto",
|
|
":external-protos",
|
|
],
|
|
|
|
output_extension: "proto.h",
|
|
}
|
|
`),
|
|
}),
|
|
).RunTest(t)
|
|
|
|
exportedIncludeDir := "out/soong/.intermediates/package-dir/module-name/gen/gensrcs"
|
|
gen := result.Module("module-name", "").(*Module)
|
|
|
|
android.AssertPathsRelativeToTopEquals(
|
|
t,
|
|
"include path",
|
|
[]string{exportedIncludeDir},
|
|
gen.exportedIncludeDirs,
|
|
)
|
|
android.AssertPathsRelativeToTopEquals(
|
|
t,
|
|
"files",
|
|
[]string{
|
|
exportedIncludeDir + "/package-dir/src/foo.a.b.c.proto.h",
|
|
exportedIncludeDir + "/external-protos/path/baz/baz.a.b.c.proto.h",
|
|
exportedIncludeDir + "/external-protos/path/bar.a.b.c.proto.h",
|
|
},
|
|
gen.outputFiles,
|
|
)
|
|
}
|
|
|
|
func TestPrebuiltTool(t *testing.T) {
|
|
testcases := []struct {
|
|
name string
|
|
bp string
|
|
expectedToolName string
|
|
}{
|
|
{
|
|
name: "source only",
|
|
bp: `
|
|
tool { name: "tool" }
|
|
`,
|
|
expectedToolName: "bin/tool",
|
|
},
|
|
{
|
|
name: "prebuilt only",
|
|
bp: `
|
|
prebuilt_tool { name: "tool" }
|
|
`,
|
|
expectedToolName: "prebuilt_bin/tool",
|
|
},
|
|
{
|
|
name: "source preferred",
|
|
bp: `
|
|
tool { name: "tool" }
|
|
prebuilt_tool { name: "tool" }
|
|
`,
|
|
expectedToolName: "bin/tool",
|
|
},
|
|
{
|
|
name: "prebuilt preferred",
|
|
bp: `
|
|
tool { name: "tool" }
|
|
prebuilt_tool { name: "tool", prefer: true }
|
|
`,
|
|
expectedToolName: "prebuilt_bin/prebuilt_tool",
|
|
},
|
|
{
|
|
name: "source disabled",
|
|
bp: `
|
|
tool { name: "tool", enabled: false }
|
|
prebuilt_tool { name: "tool" }
|
|
`,
|
|
expectedToolName: "prebuilt_bin/prebuilt_tool",
|
|
},
|
|
}
|
|
|
|
for _, test := range testcases {
|
|
t.Run(test.name, func(t *testing.T) {
|
|
result := prepareForGenRuleTest.RunTestWithBp(t, test.bp+`
|
|
genrule {
|
|
name: "gen",
|
|
tools: ["tool"],
|
|
out: ["foo"],
|
|
cmd: "$(location tool)",
|
|
}
|
|
`)
|
|
gen := result.Module("gen", "").(*Module)
|
|
expectedCmd := "__SBOX_SANDBOX_DIR__/tools/out/" + test.expectedToolName
|
|
android.AssertStringEquals(t, "command", expectedCmd, gen.rawCommands[0])
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestGenruleWithGlobPaths(t *testing.T) {
|
|
testcases := []struct {
|
|
name string
|
|
bp string
|
|
additionalFiles android.MockFS
|
|
expectedCmd string
|
|
}{
|
|
{
|
|
name: "single file in directory with $ sign",
|
|
bp: `
|
|
genrule {
|
|
name: "gen",
|
|
srcs: ["inn*.txt"],
|
|
out: ["out.txt"],
|
|
cmd: "cp $(in) $(out)",
|
|
}
|
|
`,
|
|
additionalFiles: android.MockFS{"inn$1.txt": nil},
|
|
expectedCmd: "cp 'inn$1.txt' __SBOX_SANDBOX_DIR__/out/out.txt",
|
|
},
|
|
{
|
|
name: "multiple file in directory with $ sign",
|
|
bp: `
|
|
genrule {
|
|
name: "gen",
|
|
srcs: ["inn*.txt"],
|
|
out: ["."],
|
|
cmd: "cp $(in) $(out)",
|
|
}
|
|
`,
|
|
additionalFiles: android.MockFS{"inn$1.txt": nil, "inn$2.txt": nil},
|
|
expectedCmd: "cp 'inn$1.txt' 'inn$2.txt' __SBOX_SANDBOX_DIR__/out",
|
|
},
|
|
{
|
|
name: "file in directory with other shell unsafe character",
|
|
bp: `
|
|
genrule {
|
|
name: "gen",
|
|
srcs: ["inn*.txt"],
|
|
out: ["out.txt"],
|
|
cmd: "cp $(in) $(out)",
|
|
}
|
|
`,
|
|
additionalFiles: android.MockFS{"inn@1.txt": nil},
|
|
expectedCmd: "cp 'inn@1.txt' __SBOX_SANDBOX_DIR__/out/out.txt",
|
|
},
|
|
{
|
|
name: "glob location param with filepath containing $",
|
|
bp: `
|
|
genrule {
|
|
name: "gen",
|
|
srcs: ["**/inn*"],
|
|
out: ["."],
|
|
cmd: "cp $(in) $(location **/inn*)",
|
|
}
|
|
`,
|
|
additionalFiles: android.MockFS{"a/inn$1.txt": nil},
|
|
expectedCmd: "cp 'a/inn$1.txt' 'a/inn$1.txt'",
|
|
},
|
|
{
|
|
name: "glob locations param with filepath containing $",
|
|
bp: `
|
|
genrule {
|
|
name: "gen",
|
|
tool_files: ["**/inn*"],
|
|
out: ["out.txt"],
|
|
cmd: "cp $(locations **/inn*) $(out)",
|
|
}
|
|
`,
|
|
additionalFiles: android.MockFS{"a/inn$1.txt": nil},
|
|
expectedCmd: "cp '__SBOX_SANDBOX_DIR__/tools/src/a/inn$1.txt' __SBOX_SANDBOX_DIR__/out/out.txt",
|
|
},
|
|
}
|
|
|
|
for _, test := range testcases {
|
|
t.Run(test.name, func(t *testing.T) {
|
|
result := android.GroupFixturePreparers(
|
|
prepareForGenRuleTest,
|
|
android.FixtureMergeMockFs(test.additionalFiles),
|
|
).RunTestWithBp(t, test.bp)
|
|
gen := result.Module("gen", "").(*Module)
|
|
android.AssertStringEquals(t, "command", test.expectedCmd, gen.rawCommands[0])
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestGenruleUsesOrderOnlyBuildNumberFile(t *testing.T) {
|
|
testCases := []struct {
|
|
name string
|
|
bp string
|
|
fs android.MockFS
|
|
expectedError string
|
|
expectedCommand string
|
|
}{
|
|
{
|
|
name: "not allowed when not in allowlist",
|
|
fs: android.MockFS{
|
|
"foo/Android.bp": []byte(`
|
|
genrule {
|
|
name: "gen",
|
|
uses_order_only_build_number_file: true,
|
|
cmd: "cp $(build_number_file) $(out)",
|
|
out: ["out.txt"],
|
|
}
|
|
`),
|
|
},
|
|
expectedError: `Only allowlisted modules may use uses_order_only_build_number_file: true`,
|
|
},
|
|
{
|
|
name: "normal",
|
|
fs: android.MockFS{
|
|
"build/soong/tests/Android.bp": []byte(`
|
|
genrule {
|
|
name: "gen",
|
|
uses_order_only_build_number_file: true,
|
|
cmd: "cp $(build_number_file) $(out)",
|
|
out: ["out.txt"],
|
|
}
|
|
`),
|
|
},
|
|
expectedCommand: `cp BUILD_NUMBER_FILE __SBOX_SANDBOX_DIR__/out/out.txt`,
|
|
},
|
|
}
|
|
|
|
for _, tc := range testCases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
fixtures := android.GroupFixturePreparers(
|
|
prepareForGenRuleTest,
|
|
android.PrepareForTestWithVisibility,
|
|
android.FixtureMergeMockFs(tc.fs),
|
|
android.FixtureModifyConfigAndContext(func(config android.Config, ctx *android.TestContext) {
|
|
config.TestProductVariables.BuildNumberFile = proptools.StringPtr("build_number.txt")
|
|
}),
|
|
)
|
|
if tc.expectedError != "" {
|
|
fixtures = fixtures.ExtendWithErrorHandler(android.FixtureExpectsOneErrorPattern(tc.expectedError))
|
|
}
|
|
result := fixtures.RunTest(t)
|
|
|
|
if tc.expectedError == "" {
|
|
tc.expectedCommand = strings.ReplaceAll(tc.expectedCommand, "BUILD_NUMBER_FILE", result.Config.SoongOutDir()+"/build_number.txt")
|
|
gen := result.Module("gen", "").(*Module)
|
|
android.AssertStringEquals(t, "raw commands", tc.expectedCommand, gen.rawCommands[0])
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
type testTool struct {
|
|
android.ModuleBase
|
|
outputFile android.Path
|
|
}
|
|
|
|
func toolFactory() android.Module {
|
|
module := &testTool{}
|
|
android.InitAndroidArchModule(module, android.HostSupported, android.MultilibFirst)
|
|
return module
|
|
}
|
|
|
|
func (t *testTool) GenerateAndroidBuildActions(ctx android.ModuleContext) {
|
|
t.outputFile = ctx.InstallFile(android.PathForModuleInstall(ctx, "bin"), ctx.ModuleName(), android.PathForOutput(ctx, ctx.ModuleName()))
|
|
}
|
|
|
|
func (t *testTool) HostToolPath() android.OptionalPath {
|
|
return android.OptionalPathForPath(t.outputFile)
|
|
}
|
|
|
|
type prebuiltTestTool struct {
|
|
android.ModuleBase
|
|
prebuilt android.Prebuilt
|
|
testTool
|
|
}
|
|
|
|
func (p *prebuiltTestTool) Name() string {
|
|
return p.prebuilt.Name(p.ModuleBase.Name())
|
|
}
|
|
|
|
func (p *prebuiltTestTool) Prebuilt() *android.Prebuilt {
|
|
return &p.prebuilt
|
|
}
|
|
|
|
func (t *prebuiltTestTool) GenerateAndroidBuildActions(ctx android.ModuleContext) {
|
|
t.outputFile = ctx.InstallFile(android.PathForModuleInstall(ctx, "prebuilt_bin"), ctx.ModuleName(), android.PathForOutput(ctx, ctx.ModuleName()))
|
|
}
|
|
|
|
func prebuiltToolFactory() android.Module {
|
|
module := &prebuiltTestTool{}
|
|
android.InitPrebuiltModuleWithoutSrcs(module)
|
|
android.InitAndroidArchModule(module, android.HostSupported, android.MultilibFirst)
|
|
return module
|
|
}
|
|
|
|
var _ android.HostToolProvider = (*testTool)(nil)
|
|
var _ android.HostToolProvider = (*prebuiltTestTool)(nil)
|
|
|
|
type testOutputProducer struct {
|
|
android.ModuleBase
|
|
outputFile android.Path
|
|
}
|
|
|
|
func outputProducerFactory() android.Module {
|
|
module := &testOutputProducer{}
|
|
android.InitAndroidArchModule(module, android.HostSupported, android.MultilibFirst)
|
|
return module
|
|
}
|
|
|
|
func (t *testOutputProducer) GenerateAndroidBuildActions(ctx android.ModuleContext) {
|
|
t.outputFile = ctx.InstallFile(android.PathForModuleInstall(ctx, "bin"), ctx.ModuleName(), android.PathForOutput(ctx, ctx.ModuleName()))
|
|
}
|
|
|
|
type useSource struct {
|
|
android.ModuleBase
|
|
props struct {
|
|
Srcs []string `android:"path"`
|
|
}
|
|
srcs android.Paths
|
|
}
|
|
|
|
func (s *useSource) GenerateAndroidBuildActions(ctx android.ModuleContext) {
|
|
s.srcs = android.PathsForModuleSrc(ctx, s.props.Srcs)
|
|
}
|
|
|
|
func useSourceFactory() android.Module {
|
|
module := &useSource{}
|
|
module.AddProperties(&module.props)
|
|
android.InitAndroidModule(module)
|
|
return module
|
|
}
|