Export OUT_DIR variable to rust-project.json

This variable is required by rust-analyzer to correctly process crates
that uses the include!(concat!(env!("OUT_DIR"), ...)) pattern.

Adds an initialize method to baseCompiler to save the computed path for
this directory. It is not possible to use the BeginMutator as the
BaseModuleContext does not contain enough information to use
PathForModuleOut.

Bug: 175004835
Test: SOONG_GEN_RUST_PROJECT=1 m nothing; inspect rust-project.json
Change-Id: If47b3832d3cca5712ae87773c174a61f5ee27bf8
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)