Add gensrcs module type

gensrcs allows sources to be generated by a specified command.

Change-Id: I725086fcdcd72bfe6c07fb8903e7b520678a247f
diff --git a/Blueprints b/Blueprints
index 3c0755f..9c2c94a 100644
--- a/Blueprints
+++ b/Blueprints
@@ -18,6 +18,7 @@
         "soong-cc",
         "soong-common",
         "soong-config",
+        "soong-genrule",
     ],
     srcs: [
         "cmd/soong_build/main.go",
@@ -85,6 +86,7 @@
         "blueprint-pathtools",
         "soong-common",
         "soong-config",
+        "soong-genrule",
     ],
     srcs: [
         "cc/builder.go",
@@ -100,6 +102,19 @@
     ],
 }
 
+bootstrap_go_package {
+    name: "soong-genrule",
+    pkgPath: "android/soong/genrule",
+    deps: [
+        "blueprint",
+        "blueprint-pathtools",
+        "soong-common",
+        "soong-config",
+    ],
+    srcs: [
+        "genrule/genrule.go",
+    ],
+}
 //
 // androidmk Android.mk to Blueprints translator
 //
diff --git a/build.ninja.in b/build.ninja.in
index 016e625..0135414 100644
--- a/build.ninja.in
+++ b/build.ninja.in
@@ -53,7 +53,7 @@
 # Variant:
 # Type:    bootstrap_go_binary
 # Factory: blueprint/bootstrap.newGoBinaryModule
-# Defined: build/soong/Blueprints:107:1
+# Defined: build/soong/Blueprints:122:1
 
 build .bootstrap/androidmk/obj/androidmk.a: g.bootstrap.gc $
         ${g.bootstrap.srcDir}/build/soong/androidmk/cmd/androidmk/android.go $
@@ -79,7 +79,7 @@
 # Variant:
 # Type:    bootstrap_go_package
 # Factory: blueprint/bootstrap.newGoPackageModule
-# Defined: build/soong/Blueprints:120:1
+# Defined: build/soong/Blueprints:135:1
 
 build .bootstrap/androidmk-parser/pkg/android/soong/androidmk/parser.a: $
         g.bootstrap.gc $
@@ -274,7 +274,7 @@
 # Variant:
 # Type:    bootstrap_go_package
 # Factory: blueprint/bootstrap.newGoPackageModule
-# Defined: build/soong/Blueprints:80:1
+# Defined: build/soong/Blueprints:81:1
 
 build .bootstrap/soong-cc/pkg/android/soong/cc.a: g.bootstrap.gc $
         ${g.bootstrap.srcDir}/build/soong/cc/builder.go $
@@ -294,8 +294,9 @@
         .bootstrap/blueprint-bootstrap/pkg/blueprint/bootstrap.a $
         .bootstrap/soong-glob/pkg/android/soong/glob.a $
         .bootstrap/soong-common/pkg/android/soong/common.a $
-        .bootstrap/soong-config/pkg/android/soong/config.a
-    incFlags = -I .bootstrap/blueprint-parser/pkg -I .bootstrap/blueprint-proptools/pkg -I .bootstrap/blueprint/pkg -I .bootstrap/blueprint-pathtools/pkg -I .bootstrap/blueprint-deptools/pkg -I .bootstrap/blueprint-bootstrap/pkg -I .bootstrap/soong-glob/pkg -I .bootstrap/soong-common/pkg -I .bootstrap/soong-config/pkg
+        .bootstrap/soong-config/pkg/android/soong/config.a $
+        .bootstrap/soong-genrule/pkg/android/soong/genrule.a
+    incFlags = -I .bootstrap/blueprint-parser/pkg -I .bootstrap/blueprint-proptools/pkg -I .bootstrap/blueprint/pkg -I .bootstrap/blueprint-pathtools/pkg -I .bootstrap/blueprint-deptools/pkg -I .bootstrap/blueprint-bootstrap/pkg -I .bootstrap/soong-glob/pkg -I .bootstrap/soong-common/pkg -I .bootstrap/soong-config/pkg -I .bootstrap/soong-genrule/pkg
     pkgPath = android/soong/cc
 default .bootstrap/soong-cc/pkg/android/soong/cc.a
 
@@ -304,7 +305,7 @@
 # Variant:
 # Type:    bootstrap_go_package
 # Factory: blueprint/bootstrap.newGoPackageModule
-# Defined: build/soong/Blueprints:49:1
+# Defined: build/soong/Blueprints:50:1
 
 build .bootstrap/soong-common/pkg/android/soong/common.a: g.bootstrap.gc $
         ${g.bootstrap.srcDir}/build/soong/common/arch.go $
@@ -330,7 +331,7 @@
 # Variant:
 # Type:    bootstrap_go_package
 # Factory: blueprint/bootstrap.newGoPackageModule
-# Defined: build/soong/Blueprints:67:1
+# Defined: build/soong/Blueprints:68:1
 
 build .bootstrap/soong-config/pkg/android/soong/config.a: g.bootstrap.gc $
         ${g.bootstrap.srcDir}/build/soong/config/config.go | $
@@ -348,11 +349,34 @@
 default .bootstrap/soong-config/pkg/android/soong/config.a
 
 # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+# Module:  soong-genrule
+# Variant:
+# Type:    bootstrap_go_package
+# Factory: blueprint/bootstrap.newGoPackageModule
+# Defined: build/soong/Blueprints:105:1
+
+build .bootstrap/soong-genrule/pkg/android/soong/genrule.a: g.bootstrap.gc $
+        ${g.bootstrap.srcDir}/build/soong/genrule/genrule.go | $
+        ${g.bootstrap.gcCmd} $
+        .bootstrap/blueprint-parser/pkg/blueprint/parser.a $
+        .bootstrap/blueprint-proptools/pkg/blueprint/proptools.a $
+        .bootstrap/blueprint/pkg/blueprint.a $
+        .bootstrap/blueprint-pathtools/pkg/blueprint/pathtools.a $
+        .bootstrap/blueprint-deptools/pkg/blueprint/deptools.a $
+        .bootstrap/blueprint-bootstrap/pkg/blueprint/bootstrap.a $
+        .bootstrap/soong-glob/pkg/android/soong/glob.a $
+        .bootstrap/soong-common/pkg/android/soong/common.a $
+        .bootstrap/soong-config/pkg/android/soong/config.a
+    incFlags = -I .bootstrap/blueprint-parser/pkg -I .bootstrap/blueprint-proptools/pkg -I .bootstrap/blueprint/pkg -I .bootstrap/blueprint-pathtools/pkg -I .bootstrap/blueprint-deptools/pkg -I .bootstrap/blueprint-bootstrap/pkg -I .bootstrap/soong-glob/pkg -I .bootstrap/soong-common/pkg -I .bootstrap/soong-config/pkg
+    pkgPath = android/soong/genrule
+default .bootstrap/soong-genrule/pkg/android/soong/genrule.a
+
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
 # Module:  soong-glob
 # Variant:
 # Type:    bootstrap_go_package
 # Factory: blueprint/bootstrap.newGoPackageModule
-# Defined: build/soong/Blueprints:38:1
+# Defined: build/soong/Blueprints:39:1
 
 build .bootstrap/soong-glob/pkg/android/soong/glob.a: g.bootstrap.gc $
         ${g.bootstrap.srcDir}/build/soong/glob/glob.go | ${g.bootstrap.gcCmd} $
@@ -380,14 +404,15 @@
         .bootstrap/soong-glob/pkg/android/soong/glob.a $
         .bootstrap/soong-common/pkg/android/soong/common.a $
         .bootstrap/soong-config/pkg/android/soong/config.a $
+        .bootstrap/soong-genrule/pkg/android/soong/genrule.a $
         .bootstrap/soong-cc/pkg/android/soong/cc.a
-    incFlags = -I .bootstrap/blueprint-parser/pkg -I .bootstrap/blueprint-proptools/pkg -I .bootstrap/blueprint/pkg -I .bootstrap/blueprint-deptools/pkg -I .bootstrap/blueprint-pathtools/pkg -I .bootstrap/blueprint-bootstrap/pkg -I .bootstrap/soong-glob/pkg -I .bootstrap/soong-common/pkg -I .bootstrap/soong-config/pkg -I .bootstrap/soong-cc/pkg
+    incFlags = -I .bootstrap/blueprint-parser/pkg -I .bootstrap/blueprint-proptools/pkg -I .bootstrap/blueprint/pkg -I .bootstrap/blueprint-deptools/pkg -I .bootstrap/blueprint-pathtools/pkg -I .bootstrap/blueprint-bootstrap/pkg -I .bootstrap/soong-glob/pkg -I .bootstrap/soong-common/pkg -I .bootstrap/soong-config/pkg -I .bootstrap/soong-genrule/pkg -I .bootstrap/soong-cc/pkg
     pkgPath = soong_build
 default .bootstrap/soong_build/obj/soong_build.a
 
 build .bootstrap/soong_build/obj/a.out: g.bootstrap.link $
         .bootstrap/soong_build/obj/soong_build.a | ${g.bootstrap.linkCmd}
-    libDirFlags = -L .bootstrap/blueprint-parser/pkg -L .bootstrap/blueprint-proptools/pkg -L .bootstrap/blueprint/pkg -L .bootstrap/blueprint-deptools/pkg -L .bootstrap/blueprint-pathtools/pkg -L .bootstrap/blueprint-bootstrap/pkg -L .bootstrap/soong-glob/pkg -L .bootstrap/soong-common/pkg -L .bootstrap/soong-config/pkg -L .bootstrap/soong-cc/pkg
+    libDirFlags = -L .bootstrap/blueprint-parser/pkg -L .bootstrap/blueprint-proptools/pkg -L .bootstrap/blueprint/pkg -L .bootstrap/blueprint-deptools/pkg -L .bootstrap/blueprint-pathtools/pkg -L .bootstrap/blueprint-bootstrap/pkg -L .bootstrap/soong-glob/pkg -L .bootstrap/soong-common/pkg -L .bootstrap/soong-config/pkg -L .bootstrap/soong-genrule/pkg -L .bootstrap/soong-cc/pkg
 default .bootstrap/soong_build/obj/a.out
 
 build .bootstrap/bin/soong_build: g.bootstrap.cp $
@@ -399,7 +424,7 @@
 # Variant:
 # Type:    bootstrap_go_binary
 # Factory: blueprint/bootstrap.newGoBinaryModule
-# Defined: build/soong/Blueprints:28:1
+# Defined: build/soong/Blueprints:29:1
 
 build .bootstrap/soong_glob/obj/soong_glob.a: g.bootstrap.gc $
         ${g.bootstrap.srcDir}/build/soong/cmd/soong_glob/soong_glob.go | $
diff --git a/cc/cc.go b/cc/cc.go
index d562421..3ffe26f 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -1,3 +1,4 @@
+// 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.
@@ -25,6 +26,7 @@
 	"strings"
 
 	"android/soong/common"
+	"android/soong/genrule"
 )
 
 type Config interface {
@@ -284,7 +286,7 @@
 
 	props = append(props, &base.properties, &base.unused)
 
-	return common.InitAndroidModule(module, hod, multilib, props...)
+	return common.InitAndroidArchModule(module, hod, multilib, props...)
 }
 
 func (c *ccBase) GenerateAndroidBuildActions(ctx common.AndroidModuleContext) {
@@ -313,6 +315,13 @@
 		return
 	}
 
+	generatedObjFiles := c.compileGeneratedObjs(ctx, flags, deps)
+	if ctx.Failed() {
+		return
+	}
+
+	objFiles = append(objFiles, generatedObjFiles...)
+
 	c.ccModuleType().compileModule(ctx, flags, deps, objFiles)
 	if ctx.Failed() {
 		return
@@ -578,6 +587,28 @@
 	return c.customCompileObjs(ctx, flags, deps, "", c.properties.Srcs)
 }
 
+// Compile generated source files from dependencies
+func (c *ccBase) compileGeneratedObjs(ctx common.AndroidModuleContext, flags ccFlags,
+	deps ccDeps) []string {
+	var srcs []string
+
+	if c.properties.SkipCompileObjs {
+		return nil
+	}
+
+	ctx.VisitDirectDeps(func(module blueprint.Module) {
+		if gen, ok := module.(genrule.SourceFileGenerator); ok {
+			srcs = append(srcs, gen.GeneratedSourceFiles()...)
+		}
+	})
+
+	if len(srcs) == 0 {
+		return nil
+	}
+
+	return TransformSourceToObj(ctx, "", srcs, ccFlagsToBuilderFlags(flags))
+}
+
 func (c *ccBase) outputFile() string {
 	return ""
 }
diff --git a/cmd/soong_build/main.go b/cmd/soong_build/main.go
index d158f75..8e2887c 100644
--- a/cmd/soong_build/main.go
+++ b/cmd/soong_build/main.go
@@ -26,6 +26,7 @@
 	"android/soong/cc"
 	"android/soong/common"
 	"android/soong/config"
+	"android/soong/genrule"
 )
 
 func main() {
@@ -50,6 +51,8 @@
 	ctx.RegisterModuleType("cc_library_host_shared", cc.NewCCLibraryHostShared)
 	ctx.RegisterModuleType("cc_binary_host", cc.NewCCBinaryHost)
 
+	ctx.RegisterModuleType("gensrcs", genrule.NewGenSrcs)
+
 	// Mutators
 	ctx.RegisterEarlyMutator("arch", common.ArchMutator)
 	ctx.RegisterEarlyMutator("link", cc.LinkageMutator)
diff --git a/common/arch.go b/common/arch.go
index bc2a9d9..cb4e998 100644
--- a/common/arch.go
+++ b/common/arch.go
@@ -280,6 +280,10 @@
 		}
 	}
 
+	if len(arches) == 0 {
+		return
+	}
+
 	archNames := []string{}
 	for _, arch := range arches {
 		archNames = append(archNames, arch.String())
@@ -301,8 +305,6 @@
 	base.commonProperties.Compile_multilib = string(defaultMultilib)
 
 	base.generalProperties = append(base.generalProperties,
-		&base.commonProperties)
-	base.generalProperties = append(base.generalProperties,
 		propertyStructs...)
 
 	for _, properties := range base.generalProperties {
diff --git a/common/module.go b/common/module.go
index ba33ec6..9bdd7c1 100644
--- a/common/module.go
+++ b/common/module.go
@@ -87,11 +87,23 @@
 	MultilibFirst Multilib = "first"
 )
 
-func InitAndroidModule(m AndroidModule, hod HostOrDeviceSupported, defaultMultilib Multilib,
+func InitAndroidModule(m AndroidModule,
 	propertyStructs ...interface{}) (blueprint.Module, []interface{}) {
 
 	base := m.base()
 	base.module = m
+
+	propertyStructs = append(propertyStructs, &base.commonProperties)
+
+	return m, propertyStructs
+}
+
+func InitAndroidArchModule(m AndroidModule, hod HostOrDeviceSupported, defaultMultilib Multilib,
+	propertyStructs ...interface{}) (blueprint.Module, []interface{}) {
+
+	_, propertyStructs = InitAndroidModule(m, propertyStructs...)
+
+	base := m.base()
 	base.commonProperties.HostOrDeviceSupported = hod
 
 	if hod == HostAndDeviceSupported {
diff --git a/genrule/genrule.go b/genrule/genrule.go
new file mode 100644
index 0000000..6c8d75b
--- /dev/null
+++ b/genrule/genrule.go
@@ -0,0 +1,97 @@
+// 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 genrule
+
+import (
+	"path/filepath"
+
+	"blueprint"
+	"blueprint/pathtools"
+
+	"android/soong/common"
+)
+
+type Config interface {
+	SrcDir() string
+}
+
+var (
+	pctx = blueprint.NewPackageContext("android/soong/genrule")
+)
+
+func init() {
+	pctx.VariableConfigMethod("srcDir", Config.SrcDir)
+}
+
+type SourceFileGenerator interface {
+	GeneratedSourceFiles() []string
+}
+
+type genSrcsProperties struct {
+	// cmd: command to run on each input file.  Available variables for substitution:
+	// $in: an input file
+	// $out: the corresponding output file
+	// $srcDir: the root directory of the source tree
+	Cmd string
+
+	// srcs: list of input files
+	Srcs []string
+
+	// output_extension: extension that will be substituted for each output file
+	Output_extension string
+}
+
+func NewGenSrcs() (blueprint.Module, []interface{}) {
+	module := &genSrcs{}
+
+	return common.InitAndroidModule(module, &module.properties)
+}
+
+type genSrcs struct {
+	common.AndroidModuleBase
+
+	properties  genSrcsProperties
+	outputFiles []string
+}
+
+func (g *genSrcs) GenerateAndroidBuildActions(ctx common.AndroidModuleContext) {
+	rule := ctx.Rule(pctx, "genSrcs", blueprint.RuleParams{
+		Command: g.properties.Cmd,
+	})
+
+	srcFiles := g.properties.Srcs
+	srcFiles = pathtools.PrefixPaths(srcFiles, common.ModuleSrcDir(ctx))
+	srcFiles = common.ExpandGlobs(ctx, srcFiles)
+
+	g.outputFiles = make([]string, 0, len(srcFiles))
+
+	for _, in := range srcFiles {
+		out := pathtools.ReplaceExtension(in, g.properties.Output_extension)
+		out = filepath.Join(common.ModuleGenDir(ctx), out)
+		g.outputFiles = append(g.outputFiles, out)
+		ctx.Build(pctx, blueprint.BuildParams{
+			Rule:    rule,
+			Inputs:  []string{in},
+			Outputs: []string{out},
+			// TODO: visit dependencies to add implicit dependencies on required tools
+		})
+	}
+}
+
+var _ SourceFileGenerator = (*genSrcs)(nil)
+
+func (g *genSrcs) GeneratedSourceFiles() []string {
+	return g.outputFiles
+}