Make global C include paths optional

Only add them to the global C include paths if they exist. And make sure
to set up proper dependencies so that we notice when they are added or
removed.

Change-Id: Ia9df14f6ae6869927ad3d3a15fb5a8081f616a81
diff --git a/common/package_ctx.go b/common/package_ctx.go
index cd18b65..233da5f 100644
--- a/common/package_ctx.go
+++ b/common/package_ctx.go
@@ -37,6 +37,7 @@
 // The most common use here will be with VariableFunc, where only a config is
 // provided, and an error should be returned.
 type configErrorWrapper struct {
+	pctx   AndroidPackageContext
 	config Config
 	errors []error
 }
@@ -50,6 +51,9 @@
 func (e *configErrorWrapper) Errorf(format string, args ...interface{}) {
 	e.errors = append(e.errors, fmt.Errorf(format, args...))
 }
+func (e *configErrorWrapper) AddNinjaFileDeps(deps ...string) {
+	e.pctx.AddNinjaFileDeps(deps...)
+}
 
 // SourcePathVariable returns a Variable whose value is the source directory
 // appended with the supplied path. It may only be called during a Go package's
@@ -57,7 +61,7 @@
 // package-scoped variable's initialization.
 func (p AndroidPackageContext) SourcePathVariable(name, path string) blueprint.Variable {
 	return p.VariableFunc(name, func(config interface{}) (string, error) {
-		ctx := &configErrorWrapper{config.(Config), []error{}}
+		ctx := &configErrorWrapper{p, config.(Config), []error{}}
 		p := safePathForSource(ctx, path)
 		if len(ctx.errors) > 0 {
 			return "", ctx.errors[0]
@@ -72,7 +76,7 @@
 // package-scoped variable's initialization.
 func (p AndroidPackageContext) HostBinToolVariable(name, path string) blueprint.Variable {
 	return p.VariableFunc(name, func(config interface{}) (string, error) {
-		ctx := &configErrorWrapper{config.(Config), []error{}}
+		ctx := &configErrorWrapper{p, config.(Config), []error{}}
 		p := PathForOutput(ctx, "host", ctx.config.PrebuiltOS(), "bin", path)
 		if len(ctx.errors) > 0 {
 			return "", ctx.errors[0]
@@ -87,7 +91,7 @@
 // part of a package-scoped variable's initialization.
 func (p AndroidPackageContext) HostJavaToolVariable(name, path string) blueprint.Variable {
 	return p.VariableFunc(name, func(config interface{}) (string, error) {
-		ctx := &configErrorWrapper{config.(Config), []error{}}
+		ctx := &configErrorWrapper{p, config.(Config), []error{}}
 		p := PathForOutput(ctx, "host", ctx.config.PrebuiltOS(), "framework", path)
 		if len(ctx.errors) > 0 {
 			return "", ctx.errors[0]
@@ -102,7 +106,7 @@
 // package-scoped variable's initialization.
 func (p AndroidPackageContext) IntermediatesPathVariable(name, path string) blueprint.Variable {
 	return p.VariableFunc(name, func(config interface{}) (string, error) {
-		ctx := &configErrorWrapper{config.(Config), []error{}}
+		ctx := &configErrorWrapper{p, config.(Config), []error{}}
 		p := PathForIntermediates(ctx, path)
 		if len(ctx.errors) > 0 {
 			return "", ctx.errors[0]
@@ -111,14 +115,16 @@
 	})
 }
 
-// PrefixedPathsForSourceVariable returns a Variable whose value is the
-// list of source paths prefixed with the supplied prefix. It may only be
-// called during a Go package's initialization - either from the init()
+// PrefixedPathsForOptionalSourceVariable returns a Variable whose value is the
+// list of present source paths prefixed with the supplied prefix. It may only
+// be called during a Go package's initialization - either from the init()
 // function or as part of a package-scoped variable's initialization.
-func (p AndroidPackageContext) PrefixedPathsForSourceVariable(name, prefix string, paths []string) blueprint.Variable {
+func (p AndroidPackageContext) PrefixedPathsForOptionalSourceVariable(
+	name, prefix string, paths []string) blueprint.Variable {
+
 	return p.VariableFunc(name, func(config interface{}) (string, error) {
-		ctx := &configErrorWrapper{config.(Config), []error{}}
-		paths := PathsForSource(ctx, paths)
+		ctx := &configErrorWrapper{p, config.(Config), []error{}}
+		paths := PathsForOptionalSource(ctx, "", paths)
 		if len(ctx.errors) > 0 {
 			return "", ctx.errors[0]
 		}
diff --git a/common/paths.go b/common/paths.go
index 8a085ea..e0d4914 100644
--- a/common/paths.go
+++ b/common/paths.go
@@ -21,6 +21,8 @@
 	"reflect"
 	"strings"
 
+	"android/soong/glob"
+
 	"github.com/google/blueprint"
 	"github.com/google/blueprint/pathtools"
 )
@@ -29,6 +31,7 @@
 // Path methods.
 type PathContext interface {
 	Config() interface{}
+	AddNinjaFileDeps(deps ...string)
 }
 
 var _ PathContext = blueprint.SingletonContext(nil)
@@ -177,6 +180,20 @@
 	return ret
 }
 
+// PathsForOptionalSource returns a list of Paths rooted from SrcDir that are
+// found in the tree. If any are not found, they are omitted from the list,
+// and dependencies are added so that we're re-run when they are added.
+func PathsForOptionalSource(ctx PathContext, intermediates string, paths []string) Paths {
+	ret := make(Paths, 0, len(paths))
+	for _, path := range paths {
+		p := OptionalPathForSource(ctx, intermediates, path)
+		if p.Valid() {
+			ret = append(ret, p.Path())
+		}
+	}
+	return ret
+}
+
 // PathsForModuleSrc returns Paths rooted from the module's local source
 // directory
 func PathsForModuleSrc(ctx AndroidModuleContext, paths []string) Paths {
@@ -319,7 +336,12 @@
 // OptionalPathForSource returns an OptionalPath with the SourcePath if the
 // path exists, or an empty OptionalPath if it doesn't exist. Dependencies are added
 // so that the ninja file will be regenerated if the state of the path changes.
-func OptionalPathForSource(ctx blueprint.SingletonContext, intermediates string, paths ...string) OptionalPath {
+func OptionalPathForSource(ctx PathContext, intermediates string, paths ...string) OptionalPath {
+	if len(paths) == 0 {
+		// For when someone forgets the 'intermediates' argument
+		panic("Missing path(s)")
+	}
+
 	p := validatePath(ctx, paths...)
 	path := SourcePath{basePath{p, pathConfig(ctx)}}
 
@@ -338,16 +360,39 @@
 		return OptionalPath{}
 	}
 
-	// Use glob to produce proper dependencies, even though we only want
-	// a single file.
-	files, err := Glob(ctx, PathForIntermediates(ctx, intermediates).String(), path.String(), nil)
-	if err != nil {
-		reportPathError(ctx, "glob: %s", err.Error())
+	if glob.IsGlob(path.String()) {
+		reportPathError(ctx, "path may not contain a glob: %s", path.String())
 		return OptionalPath{}
 	}
 
-	if len(files) == 0 {
-		return OptionalPath{}
+	if gctx, ok := ctx.(globContext); 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)
+		if err != nil {
+			reportPathError(ctx, "glob: %s", err.Error())
+			return OptionalPath{}
+		}
+
+		if len(files) == 0 {
+			return OptionalPath{}
+		}
+	} else {
+		// We cannot add build statements in this context, so we fall back to
+		// AddNinjaFileDeps
+		files, dirs, err := pathtools.Glob(path.String())
+		if err != nil {
+			reportPathError(ctx, "glob: %s", err.Error())
+			return OptionalPath{}
+		}
+
+		ctx.AddNinjaFileDeps(dirs...)
+
+		if len(files) == 0 {
+			return OptionalPath{}
+		}
+
+		ctx.AddNinjaFileDeps(path.String())
 	}
 	return OptionalPathForPath(path)
 }
@@ -377,6 +422,9 @@
 	}
 	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) {
+		reportPathError(ctx, "Path may not contain a glob: %s", dir)
+	}
 	paths, err := Glob(ctx, PathForModuleOut(ctx, "overlay").String(), dir, []string{})
 	if err != nil {
 		reportPathError(ctx, "glob: %s", err.Error())