Merge "Export OUT_DIR variable to rust-project.json"
diff --git a/rust/builder.go b/rust/builder.go
index 6326124..9d462d4 100644
--- a/rust/builder.go
+++ b/rust/builder.go
@@ -194,8 +194,7 @@
 	}
 
 	if len(deps.SrcDeps) > 0 {
-		genSubDir := "out/"
-		moduleGenDir := android.PathForModuleOut(ctx, genSubDir)
+		moduleGenDir := ctx.RustModule().compiler.CargoOutDir()
 		var outputs android.WritablePaths
 
 		for _, genSrc := range deps.SrcDeps {
@@ -208,7 +207,7 @@
 
 		ctx.Build(pctx, android.BuildParams{
 			Rule:        cp,
-			Description: "cp " + moduleGenDir.Rel(),
+			Description: "cp " + moduleGenDir.Path().Rel(),
 			Outputs:     outputs,
 			Inputs:      deps.SrcDeps,
 			Args: map[string]string{
diff --git a/rust/compiler.go b/rust/compiler.go
index c26f208..98ad7ad 100644
--- a/rust/compiler.go
+++ b/rust/compiler.go
@@ -60,6 +60,7 @@
 	InstallInData                   = iota
 
 	incorrectSourcesError = "srcs can only contain one path for a rust file and source providers prefixed by \":\""
+	genSubDir             = "out/"
 )
 
 type BaseCompilerProperties struct {
@@ -154,6 +155,10 @@
 	distFile android.OptionalPath
 	// Stripped output file. If Valid(), this file will be installed instead of outputFile.
 	strippedOutputFile android.OptionalPath
+
+	// If a crate has a source-generated dependency, a copy of the source file
+	// will be available in cargoOutDir (equivalent to Cargo OUT_DIR).
+	cargoOutDir android.ModuleOutPath
 }
 
 func (compiler *baseCompiler) Disabled() bool {
@@ -243,6 +248,14 @@
 	panic(fmt.Errorf("baseCrater doesn't know how to crate things!"))
 }
 
+func (compiler *baseCompiler) initialize(ctx ModuleContext) {
+	compiler.cargoOutDir = android.PathForModuleOut(ctx, genSubDir)
+}
+
+func (compiler *baseCompiler) CargoOutDir() android.OptionalPath {
+	return android.OptionalPathForPath(compiler.cargoOutDir)
+}
+
 func (compiler *baseCompiler) isDependencyRoot() bool {
 	return false
 }
diff --git a/rust/project_json.go b/rust/project_json.go
index 32ce6f4..8d3d250 100644
--- a/rust/project_json.go
+++ b/rust/project_json.go
@@ -45,11 +45,12 @@
 }
 
 type rustProjectCrate struct {
-	DisplayName string           `json:"display_name"`
-	RootModule  string           `json:"root_module"`
-	Edition     string           `json:"edition,omitempty"`
-	Deps        []rustProjectDep `json:"deps"`
-	Cfgs        []string         `json:"cfgs"`
+	DisplayName string            `json:"display_name"`
+	RootModule  string            `json:"root_module"`
+	Edition     string            `json:"edition,omitempty"`
+	Deps        []rustProjectDep  `json:"deps"`
+	Cfgs        []string          `json:"cfgs"`
+	Env         map[string]string `json:"env"`
 }
 
 type rustProjectJson struct {
@@ -136,7 +137,7 @@
 		}
 	})
 	if !foundSource {
-		fmt.Errorf("No valid source for source provider found: %v\n", rModule)
+		ctx.Errorf("No valid source for source provider found: %v\n", rModule)
 	}
 	return sourceSrc, foundSource
 }
@@ -220,7 +221,7 @@
 func (singleton *projectGeneratorSingleton) addCrate(ctx android.SingletonContext, rModule *Module, comp *baseCompiler) (int, bool) {
 	rootModule, ok := crateSource(ctx, rModule, comp)
 	if !ok {
-		fmt.Errorf("Unable to find source for valid module: %v", rModule)
+		ctx.Errorf("Unable to find source for valid module: %v", rModule)
 		return 0, false
 	}
 
@@ -230,6 +231,11 @@
 		Edition:     comp.edition(),
 		Deps:        make([]rustProjectDep, 0),
 		Cfgs:        make([]string, 0),
+		Env:         make(map[string]string),
+	}
+
+	if comp.CargoOutDir().Valid() {
+		crate.Env["OUT_DIR"] = comp.CargoOutDir().String()
 	}
 
 	deps := make(map[string]int)
diff --git a/rust/project_json_test.go b/rust/project_json_test.go
index ba66215..289bcb8 100644
--- a/rust/project_json_test.go
+++ b/rust/project_json_test.go
@@ -190,8 +190,8 @@
 				}
 			}
 		}
-		// Check that liba depends on libbindings1
 		if strings.Contains(rootModule, "d/src/lib.rs") {
+			// Check that libd depends on libbindings1
 			found := false
 			for _, depName := range validateDependencies(t, crate) {
 				if depName == "bindings1" {
@@ -200,8 +200,17 @@
 				}
 			}
 			if !found {
-				t.Errorf("liba does not depend on libbindings1: %v", crate)
+				t.Errorf("libd does not depend on libbindings1: %v", crate)
 			}
+			// Check that OUT_DIR is populated.
+			env, ok := crate["env"].(map[string]interface{})
+			if !ok {
+				t.Errorf("libd does not have its environment variables set: %v", crate)
+			}
+			if _, ok = env["OUT_DIR"]; !ok {
+				t.Errorf("libd does not have its OUT_DIR set: %v", env)
+			}
+
 		}
 	}
 }
diff --git a/rust/rust.go b/rust/rust.go
index dc23abb..8ebdb72 100644
--- a/rust/rust.go
+++ b/rust/rust.go
@@ -320,12 +320,16 @@
 }
 
 type compiler interface {
+	initialize(ctx ModuleContext)
 	compilerFlags(ctx ModuleContext, flags Flags) Flags
 	compilerProps() []interface{}
 	compile(ctx ModuleContext, flags Flags, deps PathDeps) android.Path
 	compilerDeps(ctx DepsContext, deps Deps) Deps
 	crateName() string
 
+	// Output directory in which source-generated code from dependencies is
+	// copied. This is equivalent to Cargo's OUT_DIR variable.
+	CargoOutDir() android.OptionalPath
 	inData() bool
 	install(ctx ModuleContext)
 	relativeInstallPath() string
@@ -711,6 +715,7 @@
 	}
 
 	if mod.compiler != nil && !mod.compiler.Disabled() {
+		mod.compiler.initialize(ctx)
 		outputFile := mod.compiler.compile(ctx, flags, deps)
 
 		mod.outputFile = android.OptionalPathForPath(outputFile)