Merge "rust: Add libstd linkage mutator for rlibs."

This commit is contained in:
Ivan Lozano 2020-09-21 19:38:28 +00:00 committed by Gerrit Code Review
commit 4de88a62c1
12 changed files with 214 additions and 38 deletions

View File

@ -178,6 +178,10 @@ func (proto *protobufDecorator) AndroidMk(ctx AndroidMkContext, ret *android.And
}
func (compiler *baseCompiler) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) {
if compiler.path == (android.InstallPath{}) {
return
}
var unstrippedOutputFile android.OptionalPath
// Soong installation is only supported for host modules. Have Make
// installation trigger Soong installation.

View File

@ -40,7 +40,7 @@ func TestBinaryLinkage(t *testing.T) {
fizzBuzzHost := ctx.ModuleForTests("fizz-buzz", "linux_glibc_x86_64").Module().(*Module)
fizzBuzzDevice := ctx.ModuleForTests("fizz-buzz", "android_arm64_armv8-a").Module().(*Module)
if !android.InList("libfoo", fizzBuzzHost.Properties.AndroidMkRlibs) {
if !android.InList("libfoo.rlib-std", fizzBuzzHost.Properties.AndroidMkRlibs) {
t.Errorf("rustlibs dependency libfoo should be an rlib dep for host modules")
}

View File

@ -146,8 +146,13 @@ func (compiler *baseCompiler) coverageOutputZipPath() android.OptionalPath {
panic("baseCompiler does not implement coverageOutputZipPath()")
}
func (compiler *baseCompiler) static() bool {
return false
func (compiler *baseCompiler) staticStd(ctx *depsContext) bool {
// For devices, we always link stdlibs in as dylibs by default.
if ctx.Device() {
return false
} else {
return true
}
}
var _ compiler = (*baseCompiler)(nil)
@ -221,15 +226,7 @@ func (compiler *baseCompiler) compilerDeps(ctx DepsContext, deps Deps) Deps {
stdlib = stdlib + "_" + ctx.toolchain().RustTriple()
}
// For devices, we always link stdlibs in as dylibs except for ffi static libraries.
// (rustc does not support linking libstd as a dylib for ffi static libraries)
if ctx.Host() {
deps.Rustlibs = append(deps.Rustlibs, stdlib)
} else if ctx.RustModule().compiler.static() {
deps.Rlibs = append(deps.Rlibs, stdlib)
} else {
deps.Dylibs = append(deps.Dylibs, stdlib)
}
deps.Stdlibs = append(deps.Stdlibs, stdlib)
}
}
return deps

View File

@ -191,7 +191,7 @@ func TestStdDeviceLinkage(t *testing.T) {
crate_name: "foo",
}`)
fizz := ctx.ModuleForTests("fizz", "android_arm64_armv8-a").Module().(*Module)
fooRlib := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_rlib").Module().(*Module)
fooRlib := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_rlib_dylib-std").Module().(*Module)
fooDylib := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_dylib").Module().(*Module)
if !android.InList("libstd", fizz.Properties.AndroidMkDylibs) {

View File

@ -154,12 +154,12 @@ func TestCoverageZip(t *testing.T) {
}
// Make sure the expected inputs are provided to the zip rule.
if !android.SuffixInList(fizzZipInputs, "android_arm64_armv8-a_rlib_cov/librlib.gcno") ||
if !android.SuffixInList(fizzZipInputs, "android_arm64_armv8-a_rlib_dylib-std_cov/librlib.gcno") ||
!android.SuffixInList(fizzZipInputs, "android_arm64_armv8-a_static_cov/libbaz.gcno") ||
!android.SuffixInList(fizzZipInputs, "android_arm64_armv8-a_cov/fizz.gcno") {
t.Fatalf("missing expected coverage files for rust 'fizz' binary: %#v", fizzZipInputs)
}
if !android.SuffixInList(libfooZipInputs, "android_arm64_armv8-a_rlib_cov/librlib.gcno") ||
if !android.SuffixInList(libfooZipInputs, "android_arm64_armv8-a_rlib_dylib-std_cov/librlib.gcno") ||
!android.SuffixInList(libfooZipInputs, "android_arm64_armv8-a_dylib_cov/libfoo.dylib.gcno") {
t.Fatalf("missing expected coverage files for rust 'fizz' binary: %#v", libfooZipInputs)
}

View File

@ -21,6 +21,11 @@ import (
"android/soong/android"
)
var (
DylibStdlibSuffix = ".dylib-std"
RlibStdlibSuffix = ".rlib-std"
)
func init() {
android.RegisterModuleType("rust_library", RustLibraryFactory)
android.RegisterModuleType("rust_library_dylib", RustLibraryDylibFactory)
@ -49,6 +54,9 @@ type LibraryCompilerProperties struct {
// path to include directories to pass to cc_* modules, only relevant for static/shared variants.
Include_dirs []string `android:"path,arch_variant"`
// Whether this library is part of the Rust toolchain sysroot.
Sysroot *bool
}
type LibraryMutatedProperties struct {
@ -73,6 +81,9 @@ type LibraryMutatedProperties struct {
// This variant is disabled and should not be compiled
// (used for SourceProvider variants that produce only source)
VariantIsDisabled bool `blueprint:"mutated"`
// Whether this library variant should be link libstd via rlibs
VariantIsStaticStd bool `blueprint:"mutated"`
}
type libraryDecorator struct {
@ -91,6 +102,7 @@ type libraryInterface interface {
dylib() bool
static() bool
shared() bool
sysroot() bool
// Returns true if the build options for the module have selected a particular build type
buildRlib() bool
@ -104,6 +116,10 @@ type libraryInterface interface {
setShared()
setStatic()
// Set libstd linkage
setRlibStd()
setDylibStd()
// Build a specific library variant
BuildOnlyFFI()
BuildOnlyRust()
@ -121,6 +137,10 @@ func (library *libraryDecorator) rlib() bool {
return library.MutatedProperties.VariantIsRlib
}
func (library *libraryDecorator) sysroot() bool {
return Bool(library.Properties.Sysroot)
}
func (library *libraryDecorator) dylib() bool {
return library.MutatedProperties.VariantIsDylib
}
@ -133,6 +153,11 @@ func (library *libraryDecorator) static() bool {
return library.MutatedProperties.VariantIsStatic
}
func (library *libraryDecorator) staticStd(ctx *depsContext) bool {
// libraries should only request the staticStd when building a static FFI or when variant is staticStd
return library.static() || library.MutatedProperties.VariantIsStaticStd
}
func (library *libraryDecorator) buildRlib() bool {
return library.MutatedProperties.BuildRlib && BoolDefault(library.Properties.Rlib.Enabled, true)
}
@ -163,6 +188,14 @@ func (library *libraryDecorator) setDylib() {
library.MutatedProperties.VariantIsShared = false
}
func (library *libraryDecorator) setRlibStd() {
library.MutatedProperties.VariantIsStaticStd = true
}
func (library *libraryDecorator) setDylibStd() {
library.MutatedProperties.VariantIsStaticStd = false
}
func (library *libraryDecorator) setShared() {
library.MutatedProperties.VariantIsStatic = false
library.MutatedProperties.VariantIsShared = true
@ -450,6 +483,13 @@ func (library *libraryDecorator) getStem(ctx ModuleContext) string {
return stem + String(library.baseCompiler.Properties.Suffix)
}
func (library *libraryDecorator) install(ctx ModuleContext) {
// Only shared and dylib variants make sense to install.
if library.shared() || library.dylib() {
library.baseCompiler.install(ctx)
}
}
func (library *libraryDecorator) Disabled() bool {
return library.MutatedProperties.VariantIsDisabled
}
@ -493,7 +533,6 @@ func LibraryMutator(mctx android.BottomUpMutatorContext) {
dylib := modules[1].(*Module)
rlib.compiler.(libraryInterface).setRlib()
dylib.compiler.(libraryInterface).setDylib()
if m.sourceProvider != nil {
// This library is SourceProvider generated, so the non-library-producing
// variant needs to disable it's compiler and skip installation.
@ -515,3 +554,23 @@ func LibraryMutator(mctx android.BottomUpMutatorContext) {
}
}
}
func LibstdMutator(mctx android.BottomUpMutatorContext) {
if m, ok := mctx.Module().(*Module); ok && m.compiler != nil && !m.compiler.Disabled() {
switch library := m.compiler.(type) {
case libraryInterface:
// Only create a variant if a library is actually being built.
if library.rlib() && !library.sysroot() {
variants := []string{"rlib-std", "dylib-std"}
modules := mctx.CreateLocalVariations(variants...)
rlib := modules[0].(*Module)
dylib := modules[1].(*Module)
rlib.compiler.(libraryInterface).setRlibStd()
dylib.compiler.(libraryInterface).setDylibStd()
rlib.Properties.SubName += RlibStdlibSuffix
dylib.Properties.SubName += DylibStdlibSuffix
}
}
}
}

View File

@ -37,7 +37,7 @@ func TestLibraryVariants(t *testing.T) {
}`)
// Test all variants are being built.
libfooRlib := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_rlib").Output("libfoo.rlib")
libfooRlib := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_rlib_rlib-std").Output("libfoo.rlib")
libfooDylib := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_dylib").Output("libfoo.dylib.so")
libfooStatic := ctx.ModuleForTests("libfoo.ffi", "linux_glibc_x86_64_static").Output("libfoo.ffi.a")
libfooShared := ctx.ModuleForTests("libfoo.ffi", "linux_glibc_x86_64_shared").Output("libfoo.ffi.so")
@ -182,14 +182,14 @@ func TestAutoDeps(t *testing.T) {
rustlibs: ["libbar"],
}`)
libfooRlib := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_rlib")
libfooRlib := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_rlib_rlib-std")
libfooDylib := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_dylib")
libfooStatic := ctx.ModuleForTests("libfoo.ffi", "linux_glibc_x86_64_static")
libfooShared := ctx.ModuleForTests("libfoo.ffi", "linux_glibc_x86_64_shared")
for _, static := range []android.TestingModule{libfooRlib, libfooStatic} {
if !android.InList("libbar", static.Module().(*Module).Properties.AndroidMkRlibs) {
t.Errorf("libbar not present as static dependency in static lib")
if !android.InList("libbar.rlib-std", static.Module().(*Module).Properties.AndroidMkRlibs) {
t.Errorf("libbar not present as rlib dependency in static lib")
}
if android.InList("libbar", static.Module().(*Module).Properties.AndroidMkDylibs) {
t.Errorf("libbar present as dynamic dependency in static lib")
@ -200,8 +200,8 @@ func TestAutoDeps(t *testing.T) {
if !android.InList("libbar", dyn.Module().(*Module).Properties.AndroidMkDylibs) {
t.Errorf("libbar not present as dynamic dependency in dynamic lib")
}
if android.InList("libbar", dyn.Module().(*Module).Properties.AndroidMkRlibs) {
t.Errorf("libbar present as static dependency in dynamic lib")
if android.InList("libbar.dylib-std", dyn.Module().(*Module).Properties.AndroidMkRlibs) {
t.Errorf("libbar present as rlib dependency in dynamic lib")
}
}
@ -238,3 +238,45 @@ func TestStrippedLibrary(t *testing.T) {
t.Errorf("stripped version of bar has been generated")
}
}
func TestLibstdLinkage(t *testing.T) {
ctx := testRust(t, `
rust_library {
name: "libfoo",
srcs: ["foo.rs"],
crate_name: "foo",
}
rust_ffi {
name: "libbar",
srcs: ["foo.rs"],
crate_name: "bar",
rustlibs: ["libfoo"],
}`)
libfooDylib := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_dylib").Module().(*Module)
libfooRlibStatic := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_rlib_rlib-std").Module().(*Module)
libfooRlibDynamic := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_rlib_dylib-std").Module().(*Module)
libbarShared := ctx.ModuleForTests("libbar", "android_arm64_armv8-a_shared").Module().(*Module)
libbarStatic := ctx.ModuleForTests("libbar", "android_arm64_armv8-a_static").Module().(*Module)
if !android.InList("libstd", libfooRlibStatic.Properties.AndroidMkRlibs) {
t.Errorf("rlib-std variant for device rust_library_rlib does not link libstd as an rlib")
}
if !android.InList("libstd", libfooRlibDynamic.Properties.AndroidMkDylibs) {
t.Errorf("dylib-std variant for device rust_library_rlib does not link libstd as an dylib")
}
if !android.InList("libstd", libfooDylib.Properties.AndroidMkDylibs) {
t.Errorf("Device rust_library_dylib does not link libstd as an dylib")
}
if !android.InList("libstd", libbarShared.Properties.AndroidMkDylibs) {
t.Errorf("Device rust_ffi_shared does not link libstd as an dylib")
}
if !android.InList("libstd", libbarStatic.Properties.AndroidMkRlibs) {
t.Errorf("Device rust_ffi_static does not link libstd as an rlib")
}
if !android.InList("libfoo.rlib-std", libbarStatic.Properties.AndroidMkRlibs) {
t.Errorf("Device rust_ffi_static does not link dependent rustlib rlib-std variant")
}
}

View File

@ -40,6 +40,7 @@ func init() {
android.RegisterModuleType("rust_defaults", defaultsFactory)
android.PreDepsMutators(func(ctx android.RegisterMutatorsContext) {
ctx.BottomUp("rust_libraries", LibraryMutator).Parallel()
ctx.BottomUp("rust_stdlinkage", LibstdMutator).Parallel()
ctx.BottomUp("rust_begin", BeginMutator).Parallel()
})
pctx.Import("android/soong/rust/config")
@ -237,6 +238,7 @@ type Deps struct {
Dylibs []string
Rlibs []string
Rustlibs []string
Stdlibs []string
ProcMacros []string
SharedLibs []string
StaticLibs []string
@ -293,7 +295,7 @@ type compiler interface {
Disabled() bool
SetDisabled()
static() bool
staticStd(ctx *depsContext) bool
}
type exportedFlagsProducer interface {
@ -782,14 +784,15 @@ func (mod *Module) depsToPaths(ctx android.ModuleContext) PathDeps {
directDylibDeps = append(directDylibDeps, rustDep)
mod.Properties.AndroidMkDylibs = append(mod.Properties.AndroidMkDylibs, depName)
case rlibDepTag:
rlib, ok := rustDep.compiler.(libraryInterface)
if !ok || !rlib.rlib() {
ctx.ModuleErrorf("mod %q not an rlib library", depName)
ctx.ModuleErrorf("mod %q not an rlib library", depName+rustDep.Properties.SubName)
return
}
depPaths.coverageFiles = append(depPaths.coverageFiles, rustDep.CoverageFiles()...)
directRlibDeps = append(directRlibDeps, rustDep)
mod.Properties.AndroidMkRlibs = append(mod.Properties.AndroidMkRlibs, depName)
mod.Properties.AndroidMkRlibs = append(mod.Properties.AndroidMkRlibs, depName+rustDep.Properties.SubName)
case procMacroDepTag:
directProcMacroDeps = append(directProcMacroDeps, rustDep)
mod.Properties.AndroidMkProcMacroLibs = append(mod.Properties.AndroidMkProcMacroLibs, depName)
@ -976,8 +979,19 @@ func (mod *Module) DepsMutator(actx android.BottomUpMutatorContext) {
commonDepVariations = append(commonDepVariations,
blueprint.Variation{Mutator: "image", Variation: android.CoreVariation})
}
stdLinkage := "dylib-std"
if mod.compiler.staticStd(ctx) {
stdLinkage = "rlib-std"
}
rlibDepVariations := commonDepVariations
if lib, ok := mod.compiler.(libraryInterface); !ok || !lib.sysroot() {
rlibDepVariations = append(rlibDepVariations,
blueprint.Variation{Mutator: "rust_stdlinkage", Variation: stdLinkage})
}
actx.AddVariationDependencies(
append(commonDepVariations, []blueprint.Variation{
append(rlibDepVariations, []blueprint.Variation{
{Mutator: "rust_libraries", Variation: "rlib"}}...),
rlibDepTag, deps.Rlibs...)
actx.AddVariationDependencies(
@ -987,12 +1001,27 @@ func (mod *Module) DepsMutator(actx android.BottomUpMutatorContext) {
if deps.Rustlibs != nil && !mod.compiler.Disabled() {
autoDep := mod.compiler.(autoDeppable).autoDep(ctx)
actx.AddVariationDependencies(
append(commonDepVariations, []blueprint.Variation{
{Mutator: "rust_libraries", Variation: autoDep.variation}}...),
autoDep.depTag, deps.Rustlibs...)
if autoDep.depTag == rlibDepTag {
actx.AddVariationDependencies(
append(rlibDepVariations, blueprint.Variation{Mutator: "rust_libraries", Variation: autoDep.variation}),
autoDep.depTag, deps.Rustlibs...)
} else {
actx.AddVariationDependencies(
append(commonDepVariations, blueprint.Variation{Mutator: "rust_libraries", Variation: autoDep.variation}),
autoDep.depTag, deps.Rustlibs...)
}
}
if deps.Stdlibs != nil {
if mod.compiler.staticStd(ctx) {
actx.AddVariationDependencies(
append(commonDepVariations, blueprint.Variation{Mutator: "rust_libraries", Variation: "rlib"}),
rlibDepTag, deps.Stdlibs...)
} else {
actx.AddVariationDependencies(
append(commonDepVariations, blueprint.Variation{Mutator: "rust_libraries", Variation: "dylib"}),
dylibDepTag, deps.Stdlibs...)
}
}
actx.AddVariationDependencies(append(commonDepVariations,
blueprint.Variation{Mutator: "link", Variation: "shared"}),
cc.SharedDepTag(), deps.SharedLibs...)

View File

@ -189,7 +189,7 @@ func TestDepsTracking(t *testing.T) {
t.Errorf("Dylib dependency not detected (dependency missing from AndroidMkDylibs)")
}
if !android.InList("librlib", module.Properties.AndroidMkRlibs) {
if !android.InList("librlib.rlib-std", module.Properties.AndroidMkRlibs) {
t.Errorf("Rlib dependency not detected (dependency missing from AndroidMkRlibs)")
}
@ -253,7 +253,7 @@ func TestSourceProviderDeps(t *testing.T) {
}
`)
libfoo := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_rlib").Rule("rustc")
libfoo := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_rlib_dylib-std").Rule("rustc")
if !android.SuffixInList(libfoo.Implicits.Strings(), "/out/bindings.rs") {
t.Errorf("rust_bindgen generated source not included as implicit input for libfoo; Implicits %#v", libfoo.Implicits.Strings())
}
@ -279,15 +279,15 @@ func TestSourceProviderDeps(t *testing.T) {
// Check that our bindings are picked up as crate dependencies as well
libfooMod := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_dylib").Module().(*Module)
if !android.InList("libbindings", libfooMod.Properties.AndroidMkRlibs) {
if !android.InList("libbindings.dylib-std", libfooMod.Properties.AndroidMkRlibs) {
t.Errorf("bindgen dependency not detected as a rlib dependency (dependency missing from AndroidMkRlibs)")
}
fizzBuzzMod := ctx.ModuleForTests("fizz-buzz-dep", "android_arm64_armv8-a").Module().(*Module)
if !android.InList("libbindings", fizzBuzzMod.Properties.AndroidMkRlibs) {
if !android.InList("libbindings.dylib-std", fizzBuzzMod.Properties.AndroidMkRlibs) {
t.Errorf("bindgen dependency not detected as a rlib dependency (dependency missing from AndroidMkRlibs)")
}
libprocmacroMod := ctx.ModuleForTests("libprocmacro", "linux_glibc_x86_64").Module().(*Module)
if !android.InList("libbindings", libprocmacroMod.Properties.AndroidMkRlibs) {
if !android.InList("libbindings.rlib-std", libprocmacroMod.Properties.AndroidMkRlibs) {
t.Errorf("bindgen dependency not detected as a rlib dependency (dependency missing from AndroidMkRlibs)")
}
@ -365,6 +365,6 @@ func TestMultilib(t *testing.T) {
crate_name: "foo",
}`)
_ = ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_rlib")
_ = ctx.ModuleForTests("libfoo", "android_arm_armv7-a-neon_rlib")
_ = ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_rlib_dylib-std")
_ = ctx.ModuleForTests("libfoo", "android_arm_armv7-a-neon_rlib_dylib-std")
}

View File

@ -133,3 +133,7 @@ func RustTestHostFactory() android.Module {
module, _ := NewRustTest(android.HostSupported)
return module.Init()
}
func (test *testDecorator) staticStd(ctx *depsContext) bool {
return true
}

View File

@ -17,6 +17,8 @@ package rust
import (
"strings"
"testing"
"android/soong/android"
)
func TestRustTest(t *testing.T) {
@ -33,3 +35,35 @@ func TestRustTest(t *testing.T) {
t.Errorf("wrong output path: %v; expected: %v", outPath, expectedOut)
}
}
func TestRustTestLinkage(t *testing.T) {
ctx := testRust(t, `
rust_test {
name: "my_test",
srcs: ["foo.rs"],
rustlibs: ["libfoo"],
rlibs: ["libbar"],
}
rust_library {
name: "libfoo",
srcs: ["foo.rs"],
crate_name: "foo",
}
rust_library {
name: "libbar",
srcs: ["foo.rs"],
crate_name: "bar",
}`)
testingModule := ctx.ModuleForTests("my_test", "android_arm64_armv8-a").Module().(*Module)
if !android.InList("libfoo.rlib-std", testingModule.Properties.AndroidMkRlibs) {
t.Errorf("rlib-std variant for libfoo not detected as a rustlib-defined rlib dependency for device rust_test module")
}
if !android.InList("libbar.rlib-std", testingModule.Properties.AndroidMkRlibs) {
t.Errorf("rlib-std variant for libbar not detected as an rlib dependency for device rust_test module")
}
if !android.InList("libstd", testingModule.Properties.AndroidMkRlibs) {
t.Errorf("Device rust_test module 'my_test' does not link libstd as an rlib")
}
}

View File

@ -32,6 +32,7 @@ func GatherRequiredDepsForTest() string {
srcs: ["libstd.so"],
},
host_supported: true,
sysroot: true,
}
rust_prebuilt_library {
name: "libtest_x86_64-unknown-linux-gnu",
@ -43,6 +44,7 @@ func GatherRequiredDepsForTest() string {
srcs: ["libtest.so"],
},
host_supported: true,
sysroot: true,
}
rust_prebuilt_library {
name: "libstd_x86_64-apple-darwin",
@ -54,6 +56,7 @@ func GatherRequiredDepsForTest() string {
srcs: ["libstd.so"],
},
host_supported: true,
sysroot: true,
}
rust_prebuilt_library {
name: "libtest_x86_64-apple-darwin",
@ -65,6 +68,7 @@ func GatherRequiredDepsForTest() string {
srcs: ["libtest.so"],
},
host_supported: true,
sysroot: true,
}
//////////////////////////////
// Device module requirements
@ -82,6 +86,7 @@ func GatherRequiredDepsForTest() string {
no_stdlibs: true,
host_supported: true,
native_coverage: false,
sysroot: true,
}
rust_library {
name: "libtest",
@ -90,6 +95,7 @@ func GatherRequiredDepsForTest() string {
no_stdlibs: true,
host_supported: true,
native_coverage: false,
sysroot: true,
}
rust_library {
name: "libprotobuf",
@ -134,6 +140,7 @@ func CreateTestContext() *android.TestContext {
ctx.PreDepsMutators(func(ctx android.RegisterMutatorsContext) {
// rust mutators
ctx.BottomUp("rust_libraries", LibraryMutator).Parallel()
ctx.BottomUp("rust_stdlinkage", LibstdMutator).Parallel()
ctx.BottomUp("rust_begin", BeginMutator).Parallel()
})
ctx.RegisterSingletonType("rust_project_generator", rustProjectGeneratorSingleton)