rust: Add rust_toolchain_library module.

Adds a new rust_toolchain_library module, a module which can compute the
source path from the toolchain root.

Bug: 140642453
Test: m

Change-Id: I2d90722880279533eb93d2d946ac8c31fc0b1835
diff --git a/rust/Android.bp b/rust/Android.bp
index cda2dbc..5e14da8 100644
--- a/rust/Android.bp
+++ b/rust/Android.bp
@@ -38,6 +38,7 @@
         "strip.go",
         "test.go",
         "testing.go",
+        "toolchain_library.go",
     ],
     testSrcs: [
         "benchmark_test.go",
diff --git a/rust/rust.go b/rust/rust.go
index 3cc7868..de1d65e 100644
--- a/rust/rust.go
+++ b/rust/rust.go
@@ -577,7 +577,7 @@
 
 func (mod *Module) CcLibrary() bool {
 	if mod.compiler != nil {
-		if _, ok := mod.compiler.(*libraryDecorator); ok {
+		if _, ok := mod.compiler.(libraryInterface); ok {
 			return true
 		}
 	}
@@ -1542,7 +1542,7 @@
 // Overrides ApexModule.IsInstallabeToApex()
 func (mod *Module) IsInstallableToApex() bool {
 	if mod.compiler != nil {
-		if lib, ok := mod.compiler.(*libraryDecorator); ok && (lib.shared() || lib.dylib()) {
+		if lib, ok := mod.compiler.(libraryInterface); ok && (lib.shared() || lib.dylib()) {
 			return true
 		}
 		if _, ok := mod.compiler.(*binaryDecorator); ok {
diff --git a/rust/toolchain_library.go b/rust/toolchain_library.go
new file mode 100644
index 0000000..326d529
--- /dev/null
+++ b/rust/toolchain_library.go
@@ -0,0 +1,103 @@
+//
+// Copyright (C) 2021 The Android Open Source Project
+//
+// 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 rust
+
+import (
+	"path"
+
+	"android/soong/android"
+	"android/soong/rust/config"
+)
+
+// This module is used to compile the rust toolchain libraries
+// When RUST_PREBUILTS_VERSION is set, the library will generated
+// from the given Rust version.
+func init() {
+	android.RegisterModuleType("rust_toolchain_library",
+		rustToolchainLibraryFactory)
+	android.RegisterModuleType("rust_toolchain_library_rlib",
+		rustToolchainLibraryRlibFactory)
+	android.RegisterModuleType("rust_toolchain_library_dylib",
+		rustToolchainLibraryDylibFactory)
+}
+
+type toolchainLibraryProperties struct {
+	// path to the toolchain source, relative to the top of the toolchain source
+	Toolchain_src *string `android:"arch_variant"`
+}
+
+type toolchainLibraryDecorator struct {
+	*libraryDecorator
+	Properties toolchainLibraryProperties
+}
+
+// rust_toolchain_library produces all rust variants.
+func rustToolchainLibraryFactory() android.Module {
+	module, library := NewRustLibrary(android.HostAndDeviceSupported)
+	library.BuildOnlyRust()
+
+	return initToolchainLibrary(module, library)
+}
+
+// rust_toolchain_library_dylib produces a dylib.
+func rustToolchainLibraryDylibFactory() android.Module {
+	module, library := NewRustLibrary(android.HostAndDeviceSupported)
+	library.BuildOnlyDylib()
+
+	return initToolchainLibrary(module, library)
+}
+
+// rust_toolchain_library_rlib produces an rlib.
+func rustToolchainLibraryRlibFactory() android.Module {
+	module, library := NewRustLibrary(android.HostAndDeviceSupported)
+	library.BuildOnlyRlib()
+
+	return initToolchainLibrary(module, library)
+}
+
+func initToolchainLibrary(module *Module, library *libraryDecorator) android.Module {
+	toolchainLibrary := &toolchainLibraryDecorator{
+		libraryDecorator: library,
+	}
+	module.compiler = toolchainLibrary
+	module.AddProperties(&toolchainLibrary.Properties)
+	android.AddLoadHook(module, rustSetToolchainSource)
+
+	return module.Init()
+}
+
+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))}
+
+		type props struct {
+			Srcs []string
+		}
+		p := &props{}
+		p.Srcs = newSrcs
+		ctx.AppendProperties(p)
+
+	} else {
+		ctx.ModuleErrorf("Called rustSetToolchainSource on a non-Rust Module.")
+	}
+}
+
+// GetRustPrebuiltVersion returns the RUST_PREBUILTS_VERSION env var, or the default version if it is not defined.
+func GetRustPrebuiltVersion(ctx android.LoadHookContext) string {
+	return ctx.AConfig().GetenvWithDefault("RUST_PREBUILTS_VERSION", config.RustDefaultVersion)
+}