diff options
author | Colin Cross <ccross@android.com> | 2016-11-01 11:10:25 -0700 |
---|---|---|
committer | Colin Cross <ccross@android.com> | 2016-11-04 04:54:16 +0000 |
commit | 7f19f37443f35f2fdd50f31bcc9263c002dab424 (patch) | |
tree | 1d9d16434a7c8558970017e9f3d0cdf5df0da077 /android | |
parent | 28f9094ee7d48a610c482bc5d20ceaf9a95cfaca (diff) | |
download | build_soong-7f19f37443f35f2fdd50f31bcc9263c002dab424.tar.gz build_soong-7f19f37443f35f2fdd50f31bcc9263c002dab424.tar.bz2 build_soong-7f19f37443f35f2fdd50f31bcc9263c002dab424.zip |
Move globbing to Blueprint
Move Soong's globbing-with-dependencies support into Blueprint so it can
be used for subdirs= lines in Android.bp files.
Blueprint has a slight change in behavior around subname= lines, it now
always uses the subname and doesn't fall back to Blueprints. To support
the Blueprints files in build/blueprint, use them directly with build=.
Test: build, add source file that matches glob, rebuild
Change-Id: Ifd0b0d3bc061aae0a16d6c7ca9a1cd8672656b4d
Diffstat (limited to 'android')
-rw-r--r-- | android/glob.go | 120 | ||||
-rw-r--r-- | android/module.go | 15 | ||||
-rw-r--r-- | android/paths.go | 18 | ||||
-rw-r--r-- | android/util.go | 27 |
4 files changed, 17 insertions, 163 deletions
diff --git a/android/glob.go b/android/glob.go deleted file mode 100644 index 0457cbcf..00000000 --- a/android/glob.go +++ /dev/null @@ -1,120 +0,0 @@ -// Copyright 2015 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 android - -import ( - "fmt" - "path/filepath" - - "github.com/google/blueprint" - - "android/soong/glob" -) - -// This file supports globbing source files in Blueprints files. -// -// The build.ninja file needs to be regenerated any time a file matching the glob is added -// or removed. The naive solution is to have the build.ninja file depend on all the -// traversed directories, but this will cause the regeneration step to run every time a -// non-matching file is added to a traversed directory, including backup files created by -// editors. -// -// The solution implemented here optimizes out regenerations when the directory modifications -// don't match the glob by having the build.ninja file depend on an intermedate file that -// is only updated when a file matching the glob is added or removed. The intermediate file -// depends on the traversed directories via a depfile. The depfile is used to avoid build -// errors if a directory is deleted - a direct dependency on the deleted directory would result -// in a build failure with a "missing and no known rule to make it" error. - -var ( - globCmd = filepath.Join("${bootstrap.ToolDir}", "soong_glob") - - // globRule rule traverses directories to produce a list of files that match $glob - // and writes it to $out if it has changed, and writes the directories to $out.d - globRule = pctx.AndroidStaticRule("globRule", - blueprint.RuleParams{ - Command: fmt.Sprintf(`%s -o $out $excludes "$glob"`, globCmd), - CommandDeps: []string{globCmd}, - Description: "glob $glob", - - Restat: true, - Deps: blueprint.DepsGCC, - Depfile: "$out.d", - }, - "glob", "excludes") -) - -func hasGlob(in []string) bool { - for _, s := range in { - if glob.IsGlob(s) { - return true - } - } - - return false -} - -// The subset of ModuleContext and SingletonContext needed by Glob -type globContext interface { - Build(pctx blueprint.PackageContext, params blueprint.BuildParams) - AddNinjaFileDeps(deps ...string) -} - -func Glob(ctx globContext, outDir string, globPattern string, excludes []string) ([]string, error) { - fileListFile := filepath.Join(outDir, "glob", globToString(globPattern)+".glob") - depFile := fileListFile + ".d" - - // Get a globbed file list, and write out fileListFile and depFile - files, err := glob.GlobWithDepFile(globPattern, fileListFile, depFile, excludes) - if err != nil { - return nil, err - } - - GlobRule(ctx, globPattern, excludes, fileListFile, depFile) - - // Make build.ninja depend on the fileListFile - ctx.AddNinjaFileDeps(fileListFile) - - return files, nil -} - -func GlobRule(ctx globContext, globPattern string, excludes []string, - fileListFile, depFile string) { - - // Create a rule to rebuild fileListFile if a directory in depFile changes. fileListFile - // will only be rewritten if it has changed, preventing unnecesary build.ninja regenerations. - ctx.Build(pctx, blueprint.BuildParams{ - Rule: globRule, - Outputs: []string{fileListFile}, - Args: map[string]string{ - "glob": globPattern, - "excludes": JoinWithPrefixAndQuote(excludes, "-e "), - }, - }) -} - -func globToString(glob string) string { - ret := "" - for _, c := range glob { - if c >= 'a' && c <= 'z' || - c >= 'A' && c <= 'Z' || - c >= '0' && c <= '9' || - c == '_' || c == '-' || c == '/' { - ret += string(c) - } - } - - return ret -} diff --git a/android/module.go b/android/module.go index 5894ee7e..0dae3a54 100644 --- a/android/module.go +++ b/android/module.go @@ -19,9 +19,8 @@ import ( "path/filepath" "strings" - "android/soong/glob" - "github.com/google/blueprint" + "github.com/google/blueprint/pathtools" ) var ( @@ -76,7 +75,7 @@ type ModuleContext interface { ModuleBuild(pctx blueprint.PackageContext, params ModuleBuildParams) ExpandSources(srcFiles, excludes []string) Paths - Glob(outDir, globPattern string, excludes []string) Paths + Glob(globPattern string, excludes []string) Paths InstallFile(installPath OutputPath, srcPath Path, deps ...Path) OutputPath InstallFileName(installPath OutputPath, name string, srcPath Path, deps ...Path) OutputPath @@ -509,7 +508,7 @@ func (a *androidModuleContext) ninjaError(outputs []string, err error) { } func (a *androidModuleContext) Build(pctx blueprint.PackageContext, params blueprint.BuildParams) { - if a.missingDeps != nil && params.Rule != globRule { + if a.missingDeps != nil { a.ninjaError(params.Outputs, fmt.Errorf("module %s missing dependencies: %s\n", a.ModuleName(), strings.Join(a.missingDeps, ", "))) return @@ -718,8 +717,8 @@ func (ctx *androidModuleContext) ExpandSources(srcFiles, excludes []string) Path globbedSrcFiles := make(Paths, 0, len(srcFiles)) for _, s := range srcFiles { - if glob.IsGlob(s) { - globbedSrcFiles = append(globbedSrcFiles, ctx.Glob("src_glob", filepath.Join(prefix, s), excludes)...) + if pathtools.IsGlob(s) { + globbedSrcFiles = append(globbedSrcFiles, ctx.Glob(filepath.Join(prefix, s), excludes)...) } else { globbedSrcFiles = append(globbedSrcFiles, PathForModuleSrc(ctx, s)) } @@ -728,8 +727,8 @@ func (ctx *androidModuleContext) ExpandSources(srcFiles, excludes []string) Path return globbedSrcFiles } -func (ctx *androidModuleContext) Glob(outDir, globPattern string, excludes []string) Paths { - ret, err := Glob(ctx, PathForModuleOut(ctx, outDir).String(), globPattern, excludes) +func (ctx *androidModuleContext) Glob(globPattern string, excludes []string) Paths { + ret, err := ctx.GlobWithDeps(globPattern, excludes) if err != nil { ctx.ModuleErrorf("glob: %s", err.Error()) } diff --git a/android/paths.go b/android/paths.go index 1202d6d4..1a6125a3 100644 --- a/android/paths.go +++ b/android/paths.go @@ -21,8 +21,6 @@ import ( "reflect" "strings" - "android/soong/glob" - "github.com/google/blueprint" "github.com/google/blueprint/pathtools" ) @@ -34,6 +32,10 @@ type PathContext interface { AddNinjaFileDeps(deps ...string) } +type PathGlobContext interface { + GlobWithDeps(globPattern string, excludes []string) ([]string, error) +} + var _ PathContext = blueprint.SingletonContext(nil) var _ PathContext = blueprint.ModuleContext(nil) @@ -248,7 +250,7 @@ func PathsWithOptionalDefaultForModuleSrc(ctx ModuleContext, input []string, def // Use Glob so that if the default doesn't exist, a dependency is added so that when it // is created, we're run again. path := filepath.Join(ctx.AConfig().srcDir, ctx.ModuleDir(), def) - return ctx.Glob("default", path, []string{}) + return ctx.Glob(path, []string{}) } // Strings returns the Paths in string form @@ -382,15 +384,15 @@ func OptionalPathForSource(ctx PathContext, intermediates string, paths ...strin return OptionalPath{} } - if glob.IsGlob(path.String()) { + if pathtools.IsGlob(path.String()) { reportPathError(ctx, "path may not contain a glob: %s", path.String()) return OptionalPath{} } - if gctx, ok := ctx.(globContext); ok { + if gctx, ok := ctx.(PathGlobContext); ok { // Use glob to produce proper dependencies, even though we only want // a single file. - files, err := Glob(gctx, PathForIntermediates(ctx, intermediates).String(), path.String(), nil) + files, err := gctx.GlobWithDeps(path.String(), nil) if err != nil { reportPathError(ctx, "glob: %s", err.Error()) return OptionalPath{} @@ -444,10 +446,10 @@ func (p SourcePath) OverlayPath(ctx ModuleContext, path Path) OptionalPath { } dir := filepath.Join(p.config.srcDir, p.path, relDir) // Use Glob so that we are run again if the directory is added. - if glob.IsGlob(dir) { + if pathtools.IsGlob(dir) { reportPathError(ctx, "Path may not contain a glob: %s", dir) } - paths, err := Glob(ctx, PathForModuleOut(ctx, "overlay").String(), dir, []string{}) + paths, err := ctx.GlobWithDeps(dir, []string{}) if err != nil { reportPathError(ctx, "glob: %s", err.Error()) return OptionalPath{} diff --git a/android/util.go b/android/util.go index 503fbbd4..8cee256c 100644 --- a/android/util.go +++ b/android/util.go @@ -45,33 +45,6 @@ func JoinWithPrefix(strs []string, prefix string) string { return string(ret) } -func JoinWithPrefixAndQuote(strs []string, prefix string) string { - if len(strs) == 0 { - return "" - } - - if len(strs) == 1 { - return prefix + `"` + strs[0] + `"` - } - - n := len(" ") * (len(strs) - 1) - for _, s := range strs { - n += len(prefix) + len(s) + len(`""`) - } - - ret := make([]byte, 0, n) - for i, s := range strs { - if i != 0 { - ret = append(ret, ' ') - } - ret = append(ret, prefix...) - ret = append(ret, '"') - ret = append(ret, s...) - ret = append(ret, '"') - } - return string(ret) -} - func sortedKeys(m map[string][]string) []string { s := make([]string, 0, len(m)) for k := range m { |