aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Android.bp1
-rw-r--r--android/module.go23
-rw-r--r--android/paths.go39
-rw-r--r--cc/androidmk.go17
-rw-r--r--cc/test.go12
-rw-r--r--cc/test_data_test.go204
-rw-r--r--genrule/filegroup.go8
7 files changed, 289 insertions, 15 deletions
diff --git a/Android.bp b/Android.bp
index 23cbad83..4ba69593 100644
--- a/Android.bp
+++ b/Android.bp
@@ -145,6 +145,7 @@ bootstrap_go_package {
],
testSrcs: [
"cc/cc_test.go",
+ "cc/test_data_test.go",
],
pluginFor: ["soong_build"],
}
diff --git a/android/module.go b/android/module.go
index 430563d3..b5de1adf 100644
--- a/android/module.go
+++ b/android/module.go
@@ -77,6 +77,7 @@ type ModuleContext interface {
ModuleBuild(pctx blueprint.PackageContext, params ModuleBuildParams)
ExpandSources(srcFiles, excludes []string) Paths
+ ExpandSourcesSubDir(srcFiles, excludes []string, subDir string) Paths
Glob(globPattern string, excludes []string) Paths
InstallFile(installPath OutputPath, srcPath Path, deps ...Path) OutputPath
@@ -742,9 +743,14 @@ type SourceFileProducer interface {
}
// Returns a list of paths expanded from globs and modules referenced using ":module" syntax.
-// ExpandSourceDeps must have already been called during the dependency resolution phase.
+// ExtractSourcesDeps must have already been called during the dependency resolution phase.
func (ctx *androidModuleContext) ExpandSources(srcFiles, excludes []string) Paths {
+ return ctx.ExpandSourcesSubDir(srcFiles, excludes, "")
+}
+
+func (ctx *androidModuleContext) ExpandSourcesSubDir(srcFiles, excludes []string, subDir string) Paths {
prefix := PathForModuleSrc(ctx).String()
+
for i, e := range excludes {
j := findStringInSlice(e, srcFiles)
if j != -1 {
@@ -754,23 +760,28 @@ func (ctx *androidModuleContext) ExpandSources(srcFiles, excludes []string) Path
excludes[i] = filepath.Join(prefix, e)
}
- globbedSrcFiles := make(Paths, 0, len(srcFiles))
+ expandedSrcFiles := make(Paths, 0, len(srcFiles))
for _, s := range srcFiles {
if m := SrcIsModule(s); m != "" {
module := ctx.GetDirectDepWithTag(m, SourceDepTag)
if srcProducer, ok := module.(SourceFileProducer); ok {
- globbedSrcFiles = append(globbedSrcFiles, srcProducer.Srcs()...)
+ expandedSrcFiles = append(expandedSrcFiles, srcProducer.Srcs()...)
} else {
ctx.ModuleErrorf("srcs dependency %q is not a source file producing module", m)
}
} else if pathtools.IsGlob(s) {
- globbedSrcFiles = append(globbedSrcFiles, ctx.Glob(filepath.Join(prefix, s), excludes)...)
+ globbedSrcFiles := ctx.Glob(filepath.Join(prefix, s), excludes)
+ expandedSrcFiles = append(expandedSrcFiles, globbedSrcFiles...)
+ for i, s := range expandedSrcFiles {
+ expandedSrcFiles[i] = s.(ModuleSrcPath).WithSubDir(ctx, subDir)
+ }
} else {
- globbedSrcFiles = append(globbedSrcFiles, PathForModuleSrc(ctx, s))
+ s := PathForModuleSrc(ctx, s).WithSubDir(ctx, subDir)
+ expandedSrcFiles = append(expandedSrcFiles, s)
}
}
- return globbedSrcFiles
+ return expandedSrcFiles
}
func (ctx *androidModuleContext) Glob(globPattern string, excludes []string) Paths {
diff --git a/android/paths.go b/android/paths.go
index ac7d81e6..037c98dc 100644
--- a/android/paths.go
+++ b/android/paths.go
@@ -86,6 +86,11 @@ type Path interface {
// Base returns the last element of the path
Base() string
+
+ // Rel returns the portion of the path relative to the directory it was created from. For
+ // example, Rel on a PathsForModuleSrc would return the path relative to the module source
+ // directory.
+ Rel() string
}
// WritablePath is a type of path that can be used as an output for build rules.
@@ -283,6 +288,7 @@ func (p WritablePaths) Strings() []string {
type basePath struct {
path string
config Config
+ rel string
}
func (p basePath) Ext() string {
@@ -293,6 +299,13 @@ func (p basePath) Base() string {
return filepath.Base(p.path)
}
+func (p basePath) Rel() string {
+ if p.rel != "" {
+ return p.rel
+ }
+ return p.path
+}
+
// SourcePath is a Path representing a file path rooted from SrcDir
type SourcePath struct {
basePath
@@ -304,7 +317,7 @@ var _ Path = SourcePath{}
// code that is embedding ninja variables in paths
func safePathForSource(ctx PathContext, path string) SourcePath {
p := validateSafePath(ctx, path)
- ret := SourcePath{basePath{p, pathConfig(ctx)}}
+ ret := SourcePath{basePath{p, pathConfig(ctx), ""}}
abs, err := filepath.Abs(ret.String())
if err != nil {
@@ -330,7 +343,7 @@ func safePathForSource(ctx PathContext, path string) SourcePath {
// will return a usable, but invalid SourcePath, and report a ModuleError.
func PathForSource(ctx PathContext, paths ...string) SourcePath {
p := validatePath(ctx, paths...)
- ret := SourcePath{basePath{p, pathConfig(ctx)}}
+ ret := SourcePath{basePath{p, pathConfig(ctx), ""}}
abs, err := filepath.Abs(ret.String())
if err != nil {
@@ -365,7 +378,7 @@ func OptionalPathForSource(ctx PathContext, intermediates string, paths ...strin
}
p := validatePath(ctx, paths...)
- path := SourcePath{basePath{p, pathConfig(ctx)}}
+ path := SourcePath{basePath{p, pathConfig(ctx), ""}}
abs, err := filepath.Abs(path.String())
if err != nil {
@@ -476,7 +489,7 @@ var _ Path = OutputPath{}
// OutputPath, and report a ModuleError.
func PathForOutput(ctx PathContext, paths ...string) OutputPath {
path := validatePath(ctx, paths...)
- return OutputPath{basePath{path, pathConfig(ctx)}}
+ return OutputPath{basePath{path, pathConfig(ctx), ""}}
}
func (p OutputPath) writablePath() {}
@@ -516,8 +529,10 @@ var _ resPathProvider = ModuleSrcPath{}
// PathForModuleSrc returns a ModuleSrcPath representing the paths... under the
// module's local source directory.
func PathForModuleSrc(ctx ModuleContext, paths ...string) ModuleSrcPath {
- path := validatePath(ctx, paths...)
- return ModuleSrcPath{PathForSource(ctx, ctx.ModuleDir(), path)}
+ p := validatePath(ctx, paths...)
+ path := ModuleSrcPath{PathForSource(ctx, ctx.ModuleDir(), p)}
+ path.basePath.rel = p
+ return path
}
// OptionalPathForModuleSrc returns an OptionalPath. The OptionalPath contains a
@@ -542,6 +557,18 @@ func (p ModuleSrcPath) resPathWithName(ctx ModuleContext, name string) ModuleRes
return PathForModuleRes(ctx, p.path, name)
}
+func (p ModuleSrcPath) WithSubDir(ctx ModuleContext, subdir string) ModuleSrcPath {
+ subdir = PathForModuleSrc(ctx, subdir).String()
+ var err error
+ rel, err := filepath.Rel(subdir, p.path)
+ if err != nil {
+ ctx.ModuleErrorf("source file %q is not under path %q", p.path, subdir)
+ return p
+ }
+ p.rel = rel
+ return p
+}
+
// ModuleOutPath is a Path representing a module's output directory.
type ModuleOutPath struct {
OutputPath
diff --git a/cc/androidmk.go b/cc/androidmk.go
index c0be1114..182938c6 100644
--- a/cc/androidmk.go
+++ b/cc/androidmk.go
@@ -159,6 +159,23 @@ func (test *testBinary) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkDa
if Bool(test.Properties.Test_per_src) {
ret.SubName = "_" + test.binaryDecorator.Properties.Stem
}
+
+ var testFiles []string
+ for _, d := range test.data {
+ rel := d.Rel()
+ path := d.String()
+ if !strings.HasSuffix(path, rel) {
+ panic(fmt.Errorf("path %q does not end with %q", path, rel))
+ }
+ path = strings.TrimSuffix(path, rel)
+ testFiles = append(testFiles, path+":"+rel)
+ }
+ if len(testFiles) > 0 {
+ ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) error {
+ fmt.Fprintln(w, "LOCAL_TEST_DATA := "+strings.Join(testFiles, " "))
+ return nil
+ })
+ }
}
func (test *testLibrary) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) {
diff --git a/cc/test.go b/cc/test.go
index f60996c7..d3556bf9 100644
--- a/cc/test.go
+++ b/cc/test.go
@@ -19,9 +19,8 @@ import (
"runtime"
"strings"
- "github.com/google/blueprint"
-
"android/soong/android"
+ "github.com/google/blueprint"
)
type TestProperties struct {
@@ -38,6 +37,10 @@ type TestBinaryProperties struct {
// relative_install_path. Useful if several tests need to be in the same
// directory, but test_per_src doesn't work.
No_named_install_directory *bool
+
+ // list of files or filegroup modules that provide data that should be installed alongside
+ // the test
+ Data []string
}
func init() {
@@ -191,6 +194,7 @@ type testBinary struct {
*binaryDecorator
*baseCompiler
Properties TestBinaryProperties
+ data android.Paths
}
func (test *testBinary) linkerProps() []interface{} {
@@ -205,6 +209,8 @@ func (test *testBinary) linkerInit(ctx BaseModuleContext) {
}
func (test *testBinary) linkerDeps(ctx DepsContext, deps Deps) Deps {
+ android.ExtractSourcesDeps(ctx, test.Properties.Data)
+
deps = test.testDecorator.linkerDeps(ctx, deps)
deps = test.binaryDecorator.linkerDeps(ctx, deps)
return deps
@@ -217,6 +223,8 @@ func (test *testBinary) linkerFlags(ctx ModuleContext, flags Flags) Flags {
}
func (test *testBinary) install(ctx ModuleContext, file android.Path) {
+ test.data = ctx.ExpandSources(test.Properties.Data, nil)
+
test.binaryDecorator.baseInstaller.dir = "nativetest"
test.binaryDecorator.baseInstaller.dir64 = "nativetest64"
diff --git a/cc/test_data_test.go b/cc/test_data_test.go
new file mode 100644
index 00000000..e3b1214f
--- /dev/null
+++ b/cc/test_data_test.go
@@ -0,0 +1,204 @@
+// Copyright 2017 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 (
+ "fmt"
+ "io/ioutil"
+ "os"
+ "path/filepath"
+ "testing"
+
+ "android/soong/android"
+ "github.com/google/blueprint"
+)
+
+type dataFile struct {
+ path string
+ file string
+}
+
+var testDataTests = []struct {
+ name string
+ modules string
+ data []dataFile
+}{
+ {
+ name: "data files",
+ modules: `
+ test {
+ name: "foo",
+ data: [
+ "baz",
+ "bar/baz",
+ ],
+ }`,
+ data: []dataFile{
+ {"dir", "baz"},
+ {"dir", "bar/baz"},
+ },
+ },
+ {
+ name: "filegroup",
+ modules: `
+ filegroup {
+ name: "fg",
+ srcs: [
+ "baz",
+ "bar/baz",
+ ],
+ }
+
+ test {
+ name: "foo",
+ data: [":fg"],
+ }`,
+ data: []dataFile{
+ {"dir", "baz"},
+ {"dir", "bar/baz"},
+ },
+ },
+ {
+ name: "relative filegroup",
+ modules: `
+ filegroup {
+ name: "fg",
+ srcs: [
+ "bar/baz",
+ ],
+ path: "bar",
+ }
+
+ test {
+ name: "foo",
+ data: [":fg"],
+ }`,
+ data: []dataFile{
+ {"dir/bar", "baz"},
+ },
+ },
+ {
+ name: "relative filegroup trailing slash",
+ modules: `
+ filegroup {
+ name: "fg",
+ srcs: [
+ "bar/baz",
+ ],
+ path: "bar/",
+ }
+
+ test {
+ name: "foo",
+ data: [":fg"],
+ }`,
+ data: []dataFile{
+ {"dir/bar", "baz"},
+ },
+ },
+}
+
+func TestDataTests(t *testing.T) {
+ buildDir, err := ioutil.TempDir("", "soong_test_test")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer os.RemoveAll(buildDir)
+
+ config := android.TestConfig(buildDir)
+
+ for _, test := range testDataTests {
+ t.Run(test.name, func(t *testing.T) {
+ ctx := android.NewContext()
+ ctx.MockFileSystem(map[string][]byte{
+ "Blueprints": []byte(`subdirs = ["dir"]`),
+ "dir/Blueprints": []byte(test.modules),
+ "dir/baz": nil,
+ "dir/bar/baz": nil,
+ })
+ ctx.RegisterModuleType("test", newTest)
+
+ _, errs := ctx.ParseBlueprintsFiles("Blueprints")
+ fail(t, errs)
+ _, errs = ctx.PrepareBuildActions(config)
+ fail(t, errs)
+
+ foo := findModule(ctx, "foo")
+ if foo == nil {
+ t.Fatalf("failed to find module foo")
+ }
+
+ got := foo.(*testDataTest).data
+ if len(got) != len(test.data) {
+ t.Errorf("expected %d data files, got %d",
+ len(test.data), len(got))
+ }
+
+ for i := range got {
+ if i >= len(test.data) {
+ break
+ }
+
+ path := filepath.Join(test.data[i].path, test.data[i].file)
+ if test.data[i].file != got[i].Rel() ||
+ path != got[i].String() {
+ fmt.Errorf("expected %s:%s got %s:%s",
+ path, test.data[i].file,
+ got[i].String(), got[i].Rel())
+ }
+ }
+ })
+ }
+}
+
+type testDataTest struct {
+ android.ModuleBase
+ data android.Paths
+ Properties struct {
+ Data []string
+ }
+}
+
+func newTest() (blueprint.Module, []interface{}) {
+ m := &testDataTest{}
+ return android.InitAndroidModule(m, &m.Properties)
+}
+
+func (test *testDataTest) DepsMutator(ctx android.BottomUpMutatorContext) {
+ android.ExtractSourcesDeps(ctx, test.Properties.Data)
+}
+
+func (test *testDataTest) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+ test.data = ctx.ExpandSources(test.Properties.Data, nil)
+}
+
+func findModule(ctx *blueprint.Context, name string) blueprint.Module {
+ var ret blueprint.Module
+ ctx.VisitAllModules(func(m blueprint.Module) {
+ if ctx.ModuleName(m) == name {
+ ret = m
+ }
+ })
+ return ret
+}
+
+func fail(t *testing.T, errs []error) {
+ if len(errs) > 0 {
+ for _, err := range errs {
+ t.Error(err)
+ }
+ t.FailNow()
+ }
+}
diff --git a/genrule/filegroup.go b/genrule/filegroup.go
index 9b53c9f7..c1d08a82 100644
--- a/genrule/filegroup.go
+++ b/genrule/filegroup.go
@@ -29,6 +29,12 @@ type fileGroupProperties struct {
Srcs []string
Exclude_srcs []string
+
+ // The base path to the files. May be used by other modules to determine which portion
+ // of the path to use. For example, when a filegroup is used as data in a cc_test rule,
+ // the base path is stripped off the path and the remaining path is used as the
+ // installation directory.
+ Path string
}
type fileGroup struct {
@@ -53,7 +59,7 @@ func (fg *fileGroup) DepsMutator(ctx android.BottomUpMutatorContext) {
}
func (fg *fileGroup) GenerateAndroidBuildActions(ctx android.ModuleContext) {
- fg.srcs = ctx.ExpandSources(fg.properties.Srcs, fg.properties.Exclude_srcs)
+ fg.srcs = ctx.ExpandSourcesSubDir(fg.properties.Srcs, fg.properties.Exclude_srcs, fg.properties.Path)
}
func (fg *fileGroup) Srcs() android.Paths {