add crate_root property to rust modules

The crate_root property will be used to specify the entry point for a
rustc compilation. This will allow the srcs property to be used to
collect all src inputs to rustc rather than just the entry point.

Bug: 286077158
Test: m libnum_traits
Change-Id: I1a167182305dcc11cc927d562ceed622153111d3
diff --git a/rust/binary.go b/rust/binary.go
index 1e24beb..2c9f64d 100644
--- a/rust/binary.go
+++ b/rust/binary.go
@@ -137,9 +137,14 @@
 
 func (binary *binaryDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) buildOutput {
 	fileName := binary.getStem(ctx) + ctx.toolchain().ExecutableSuffix()
-	srcPath, _ := srcPathFromModuleSrcs(ctx, binary.baseCompiler.Properties.Srcs)
 	outputFile := android.PathForModuleOut(ctx, fileName)
 	ret := buildOutput{outputFile: outputFile}
+	var crateRootPath android.Path
+	if binary.baseCompiler.Properties.Crate_root == nil {
+		crateRootPath, _ = srcPathFromModuleSrcs(ctx, binary.baseCompiler.Properties.Srcs)
+	} else {
+		crateRootPath = android.PathForModuleSrc(ctx, *binary.baseCompiler.Properties.Crate_root)
+	}
 
 	flags.RustFlags = append(flags.RustFlags, deps.depFlags...)
 	flags.LinkFlags = append(flags.LinkFlags, deps.depLinkFlags...)
@@ -154,7 +159,7 @@
 	}
 	binary.baseCompiler.unstrippedOutputFile = outputFile
 
-	ret.kytheFile = TransformSrcToBinary(ctx, srcPath, deps, flags, outputFile).kytheFile
+	ret.kytheFile = TransformSrcToBinary(ctx, crateRootPath, deps, flags, outputFile).kytheFile
 	return ret
 }
 
diff --git a/rust/compiler.go b/rust/compiler.go
index e6a7a93..d6c52e8 100644
--- a/rust/compiler.go
+++ b/rust/compiler.go
@@ -73,6 +73,15 @@
 	// If no source file is defined, a single generated source module can be defined to be used as the main source.
 	Srcs []string `android:"path,arch_variant"`
 
+	// Entry point that is passed to rustc to begin the compilation. E.g. main.rs or lib.rs.
+	// When this property is set,
+	//    * sandboxing is enabled for this module, and
+	//    * the srcs attribute is interpreted as a list of all source files potentially
+	//          used in compilation, including the entrypoint, and
+	//    * compile_data can be used to add additional files used in compilation that
+	//          not directly used as source files.
+	Crate_root *string `android:"path,arch_variant"`
+
 	// name of the lint set that should be used to validate this module.
 	//
 	// Possible values are "default" (for using a sensible set of lints
@@ -511,6 +520,8 @@
 		ctx.PropertyErrorf("srcs", "only a single generated source module can be defined without a main source file.")
 	}
 
+	// TODO: b/297264540 - once all modules are sandboxed, we need to select the proper
+	// entry point file from Srcs rather than taking the first one
 	paths := android.PathsForModuleSrc(ctx, srcs)
 	return paths[srcIndex], paths[1:]
 }
diff --git a/rust/library.go b/rust/library.go
index 3f031c1..7432a12 100644
--- a/rust/library.go
+++ b/rust/library.go
@@ -489,7 +489,7 @@
 	var outputFile android.ModuleOutPath
 	var ret buildOutput
 	var fileName string
-	srcPath := library.srcPath(ctx, deps)
+	crateRootPath := library.crateRootPath(ctx, deps)
 
 	if library.sourceProvider != nil {
 		deps.srcProviderFiles = append(deps.srcProviderFiles, library.sourceProvider.Srcs()...)
@@ -536,13 +536,13 @@
 
 	// Call the appropriate builder for this library type
 	if library.rlib() {
-		ret.kytheFile = TransformSrctoRlib(ctx, srcPath, deps, flags, outputFile).kytheFile
+		ret.kytheFile = TransformSrctoRlib(ctx, crateRootPath, deps, flags, outputFile).kytheFile
 	} else if library.dylib() {
-		ret.kytheFile = TransformSrctoDylib(ctx, srcPath, deps, flags, outputFile).kytheFile
+		ret.kytheFile = TransformSrctoDylib(ctx, crateRootPath, deps, flags, outputFile).kytheFile
 	} else if library.static() {
-		ret.kytheFile = TransformSrctoStatic(ctx, srcPath, deps, flags, outputFile).kytheFile
+		ret.kytheFile = TransformSrctoStatic(ctx, crateRootPath, deps, flags, outputFile).kytheFile
 	} else if library.shared() {
-		ret.kytheFile = TransformSrctoShared(ctx, srcPath, deps, flags, outputFile).kytheFile
+		ret.kytheFile = TransformSrctoShared(ctx, crateRootPath, deps, flags, outputFile).kytheFile
 	}
 
 	if library.rlib() || library.dylib() {
@@ -585,13 +585,15 @@
 	return ret
 }
 
-func (library *libraryDecorator) srcPath(ctx ModuleContext, _ PathDeps) android.Path {
+func (library *libraryDecorator) crateRootPath(ctx ModuleContext, _ PathDeps) android.Path {
 	if library.sourceProvider != nil {
 		// Assume the first source from the source provider is the library entry point.
 		return library.sourceProvider.Srcs()[0]
-	} else {
+	} else if library.baseCompiler.Properties.Crate_root == nil {
 		path, _ := srcPathFromModuleSrcs(ctx, library.baseCompiler.Properties.Srcs)
 		return path
+	} else {
+		return android.PathForModuleSrc(ctx, *library.baseCompiler.Properties.Crate_root)
 	}
 }
 
@@ -606,7 +608,7 @@
 		return android.OptionalPath{}
 	}
 
-	return android.OptionalPathForPath(Rustdoc(ctx, library.srcPath(ctx, deps),
+	return android.OptionalPathForPath(Rustdoc(ctx, library.crateRootPath(ctx, deps),
 		deps, flags))
 }
 
diff --git a/rust/toolchain_library.go b/rust/toolchain_library.go
index 801c0c2..e118f92 100644
--- a/rust/toolchain_library.go
+++ b/rust/toolchain_library.go
@@ -40,8 +40,10 @@
 }
 
 type toolchainLibraryProperties struct {
-	// path to the toolchain source, relative to the top of the toolchain source
-	Toolchain_src *string `android:"arch_variant"`
+	// path to the toolchain crate root, relative to the top of the toolchain source
+	Toolchain_crate_root *string `android:"arch_variant"`
+	// path to the rest of the toolchain srcs, relative to the top of the toolchain source
+	Toolchain_srcs []string `android:"arch_variant"`
 }
 
 type toolchainLibraryDecorator struct {
@@ -87,15 +89,20 @@
 func rustSetToolchainSource(ctx android.LoadHookContext) {
 	if toolchainLib, ok := ctx.Module().(*Module).compiler.(*toolchainLibraryDecorator); ok {
 		prefix := "linux-x86/" + GetRustPrebuiltVersion(ctx)
-		newSrcs := []string{path.Join(prefix, android.String(toolchainLib.Properties.Toolchain_src))}
+		versionedCrateRoot := path.Join(prefix, android.String(toolchainLib.Properties.Toolchain_crate_root))
+		versionedSrcs := make([]string, len(toolchainLib.Properties.Toolchain_srcs))
+		for i, src := range toolchainLib.Properties.Toolchain_srcs {
+			versionedSrcs[i] = path.Join(prefix, src)
+		}
 
 		type props struct {
-			Srcs []string
+			Crate_root *string
+			Srcs       []string
 		}
 		p := &props{}
-		p.Srcs = newSrcs
+		p.Crate_root = &versionedCrateRoot
+		p.Srcs = versionedSrcs
 		ctx.AppendProperties(p)
-
 	} else {
 		ctx.ModuleErrorf("Called rustSetToolchainSource on a non-Rust Module.")
 	}