[rust] Add SourceProviders as crates support.
This allows SourceProvider modules to create rust_library variants so
that generated source can be referenced as an external crate rather than
via an include macro. This is done by including rust_bindgen modules
like any other library, as a dependency in either rlibs, dylibs, or
rustlibs.
This renames the stem and flags properties for rust_bindgen modules to
source_stem and bindgen_flags, respectively. This deconflicts with the
usage in baseCompiler.
This also removes 'subName' from the Module struct and moves it over to
SourceProvider, which was the only user. This allows us to set it in
baseSourceProvider's AndroidMk; setting it in Module's AndroidMk was
causing problems finding NOTICE files for bindgen library variants.
Bug: 159064919
Test: New Soong tests pass.
Test: Local test rust_binary can use rust_bindgen module as a crate.
Change-Id: Ieb2cb614c2dd0b5aa7120541d77f6f822a6a1806
diff --git a/rust/androidmk.go b/rust/androidmk.go
index babbf91..5806017 100644
--- a/rust/androidmk.go
+++ b/rust/androidmk.go
@@ -55,7 +55,6 @@
ret := android.AndroidMkData{
OutputFile: mod.outputFile,
Include: "$(BUILD_SYSTEM)/soong_rust_prebuilt.mk",
- SubName: mod.subName,
Extra: []android.AndroidMkExtraFunc{
func(w io.Writer, outputFile android.Path) {
if len(mod.Properties.AndroidMkRlibs) > 0 {
@@ -76,9 +75,11 @@
},
},
}
- if mod.compiler != nil {
+
+ if mod.compiler != nil && !mod.compiler.Disabled() {
mod.subAndroidMk(&ret, mod.compiler)
} else if mod.sourceProvider != nil {
+ // If the compiler is disabled, this is a SourceProvider.
mod.subAndroidMk(&ret, mod.sourceProvider)
}
ret.SubName += mod.Properties.SubName
@@ -162,6 +163,7 @@
outFile := sourceProvider.outputFile
ret.Class = "ETC"
ret.OutputFile = android.OptionalPathForPath(outFile)
+ ret.SubName += sourceProvider.subName
ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) {
_, file := filepath.Split(outFile.String())
stem, suffix, _ := android.SplitFileExt(file)
diff --git a/rust/bindgen.go b/rust/bindgen.go
index e8bbb35..304f8ec 100644
--- a/rust/bindgen.go
+++ b/rust/bindgen.go
@@ -61,7 +61,7 @@
Wrapper_src *string `android:"path,arch_variant"`
// list of bindgen-specific flags and options
- Flags []string `android:"arch_variant"`
+ Bindgen_flags []string `android:"arch_variant"`
// list of clang flags required to correctly interpret the headers.
Cflags []string `android:"arch_variant"`
@@ -121,7 +121,7 @@
}
bindgenFlags := defaultBindgenFlags
- bindgenFlags = append(bindgenFlags, strings.Join(b.Properties.Flags, " "))
+ bindgenFlags = append(bindgenFlags, strings.Join(b.Properties.Bindgen_flags, " "))
wrapperFile := android.OptionalPathForModuleSrc(ctx, b.Properties.Wrapper_src)
if !wrapperFile.Valid() {
@@ -170,7 +170,13 @@
baseSourceProvider: NewSourceProvider(),
Properties: BindgenProperties{},
}
+
+ _, library := NewRustLibrary(hod)
+ library.BuildOnlyRust()
+ library.sourceProvider = bindgen
+
module.sourceProvider = bindgen
+ module.compiler = library
return module, bindgen
}
diff --git a/rust/bindgen_test.go b/rust/bindgen_test.go
index 2122ec1..c428348 100644
--- a/rust/bindgen_test.go
+++ b/rust/bindgen_test.go
@@ -24,8 +24,10 @@
rust_bindgen {
name: "libbindgen",
wrapper_src: "src/any.h",
- stem: "bindings",
- flags: ["--bindgen-flag"],
+ crate_name: "bindgen",
+ stem: "libbindgen",
+ source_stem: "bindings",
+ bindgen_flags: ["--bindgen-flag"],
cflags: ["--clang-flag"],
shared_libs: ["libfoo_shared"],
static_libs: ["libfoo_static"],
@@ -38,7 +40,6 @@
name: "libfoo_static",
export_include_dirs: ["static_include"],
}
-
`)
libbindgen := ctx.ModuleForTests("libbindgen", "android_arm64_armv8-a").Output("bindings.rs")
if !strings.Contains(libbindgen.Args["flags"], "--bindgen-flag") {
diff --git a/rust/builder_test.go b/rust/builder_test.go
index 04b67d9..5c11cb7 100644
--- a/rust/builder_test.go
+++ b/rust/builder_test.go
@@ -28,12 +28,14 @@
}
rust_bindgen {
name: "libbindings1",
- stem: "bindings",
+ source_stem: "bindings",
+ crate_name: "bindings1",
wrapper_src: "src/any.h",
}
rust_bindgen {
name: "libbindings2",
- stem: "bindings",
+ source_stem: "bindings",
+ crate_name: "bindings2",
wrapper_src: "src/any.h",
}
`)
diff --git a/rust/compiler.go b/rust/compiler.go
index 040219d..ec059c3 100644
--- a/rust/compiler.go
+++ b/rust/compiler.go
@@ -81,7 +81,10 @@
// list of C static library dependencies
Static_libs []string `android:"arch_variant"`
- // crate name, required for libraries. This must be the expected extern crate name used in source
+ // crate name, required for modules which produce Rust libraries: rust_library, rust_ffi and SourceProvider
+ // modules which create library variants (rust_bindgen). This must be the expected extern crate name used in
+ // source, and is required to conform to an enforced format matching library output files (if the output file is
+ // lib<someName><suffix>, the crate_name property must be <someName>).
Crate_name string `android:"arch_variant"`
// list of features to enable for this crate
@@ -120,6 +123,14 @@
distFile android.OptionalPath
}
+func (compiler *baseCompiler) Disabled() bool {
+ return false
+}
+
+func (compiler *baseCompiler) SetDisabled() {
+ panic("baseCompiler does not implement SetDisabled()")
+}
+
func (compiler *baseCompiler) coverageOutputZipPath() android.OptionalPath {
panic("baseCompiler does not implement coverageOutputZipPath()")
}
diff --git a/rust/library.go b/rust/library.go
index 6d5eca0..6766d61 100644
--- a/rust/library.go
+++ b/rust/library.go
@@ -69,6 +69,10 @@
VariantIsShared bool `blueprint:"mutated"`
// This variant is a static library
VariantIsStatic bool `blueprint:"mutated"`
+
+ // This variant is disabled and should not be compiled
+ // (used for SourceProvider variants that produce only source)
+ VariantIsDisabled bool `blueprint:"mutated"`
}
type libraryDecorator struct {
@@ -78,6 +82,7 @@
Properties LibraryCompilerProperties
MutatedProperties LibraryMutatedProperties
includeDirs android.Paths
+ sourceProvider SourceProvider
}
type libraryInterface interface {
@@ -367,8 +372,13 @@
func (library *libraryDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) android.Path {
var outputFile android.WritablePath
+ var srcPath android.Path
- srcPath, _ := srcPathFromModuleSrcs(ctx, library.baseCompiler.Properties.Srcs)
+ if library.sourceProvider != nil {
+ srcPath = library.sourceProvider.Srcs()[0]
+ } else {
+ srcPath, _ = srcPathFromModuleSrcs(ctx, library.baseCompiler.Properties.Srcs)
+ }
flags.RustFlags = append(flags.RustFlags, deps.depFlags...)
@@ -430,6 +440,14 @@
return stem + String(library.baseCompiler.Properties.Suffix)
}
+func (library *libraryDecorator) Disabled() bool {
+ return library.MutatedProperties.VariantIsDisabled
+}
+
+func (library *libraryDecorator) SetDisabled() {
+ library.MutatedProperties.VariantIsDisabled = true
+}
+
var validCrateName = regexp.MustCompile("[^a-zA-Z0-9_]+")
func validateLibraryStem(ctx BaseModuleContext, filename string, crate_name string) {
@@ -455,12 +473,23 @@
switch library := m.compiler.(type) {
case libraryInterface:
if library.buildRlib() && library.buildDylib() {
- modules := mctx.CreateLocalVariations("rlib", "dylib")
+ variants := []string{"rlib", "dylib"}
+ if m.sourceProvider != nil {
+ variants = append(variants, "")
+ }
+ modules := mctx.CreateLocalVariations(variants...)
+
rlib := modules[0].(*Module)
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.
+ sourceProvider := modules[2].(*Module)
+ sourceProvider.compiler.SetDisabled()
+ }
} else if library.buildRlib() {
modules := mctx.CreateLocalVariations("rlib")
modules[0].(*Module).compiler.(libraryInterface).setRlib()
@@ -468,6 +497,11 @@
modules := mctx.CreateLocalVariations("dylib")
modules[0].(*Module).compiler.(libraryInterface).setDylib()
}
+
+ if m.sourceProvider != nil {
+ // Alias the non-library variant to the empty-string variant.
+ mctx.AliasVariation("")
+ }
}
}
}
diff --git a/rust/rust.go b/rust/rust.go
index 5d383e1..1192836 100644
--- a/rust/rust.go
+++ b/rust/rust.go
@@ -63,7 +63,8 @@
AndroidMkSharedLibs []string
AndroidMkStaticLibs []string
- SubName string `blueprint:"mutated"`
+ SubName string `blueprint:"mutated"`
+
PreventInstall bool
HideFromMake bool
}
@@ -83,9 +84,9 @@
cachedToolchain config.Toolchain
sourceProvider SourceProvider
subAndroidMkOnce map[subAndroidMkProvider]bool
- outputFile android.OptionalPath
- subName string
+ outputFile android.OptionalPath
+ generatedFile android.OptionalPath
}
func (mod *Module) OutputFiles(tag string) (android.Paths, error) {
@@ -285,6 +286,9 @@
relativeInstallPath() string
nativeCoverage() bool
+
+ Disabled() bool
+ SetDisabled()
}
type exportedFlagsProducer interface {
@@ -667,16 +671,21 @@
flags, deps = mod.clippy.flags(ctx, flags, deps)
}
- if mod.compiler != nil {
+ // SourceProvider needs to call generateSource() before compiler calls compile() so it can provide the source.
+ // TODO(b/162588681) This shouldn't have to run for every variant.
+ if mod.sourceProvider != nil {
+ generatedFile := mod.sourceProvider.generateSource(ctx, deps)
+ mod.generatedFile = android.OptionalPathForPath(generatedFile)
+ mod.sourceProvider.setSubName(ctx.ModuleSubDir())
+ }
+
+ if mod.compiler != nil && !mod.compiler.Disabled() {
outputFile := mod.compiler.compile(ctx, flags, deps)
+
mod.outputFile = android.OptionalPathForPath(outputFile)
- if !mod.Properties.PreventInstall {
+ if mod.outputFile.Valid() && !mod.Properties.PreventInstall {
mod.compiler.install(ctx, mod.outputFile.Path())
}
- } else if mod.sourceProvider != nil {
- outputFile := mod.sourceProvider.generateSource(ctx, deps)
- mod.outputFile = android.OptionalPathForPath(outputFile)
- mod.subName = ctx.ModuleSubDir()
}
}
@@ -685,7 +694,8 @@
if mod.compiler != nil {
deps = mod.compiler.compilerDeps(ctx, deps)
- } else if mod.sourceProvider != nil {
+ }
+ if mod.sourceProvider != nil {
deps = mod.sourceProvider.sourceProviderDeps(ctx, deps)
}
@@ -755,11 +765,6 @@
if rustDep, ok := dep.(*Module); ok && !rustDep.CcLibraryInterface() {
//Handle Rust Modules
- linkFile := rustDep.outputFile
- if !linkFile.Valid() {
- ctx.ModuleErrorf("Invalid output file when adding dep %q to %q", depName, ctx.ModuleName())
- }
-
switch depTag {
case dylibDepTag:
dylib, ok := rustDep.compiler.(libraryInterface)
@@ -808,6 +813,12 @@
}
if depTag == dylibDepTag || depTag == rlibDepTag || depTag == procMacroDepTag {
+ linkFile := rustDep.outputFile
+ if !linkFile.Valid() {
+ ctx.ModuleErrorf("Invalid output file when adding dep %q to %q",
+ depName, ctx.ModuleName())
+ return
+ }
linkDir := linkPathFromFilePath(linkFile.Path())
if lib, ok := mod.compiler.(exportedFlagsProducer); ok {
lib.exportLinkDirs(linkDir)
@@ -826,7 +837,6 @@
return
}
}
-
linkFile := ccDep.OutputFile()
linkPath := linkPathFromFilePath(linkFile.Path())
libName := libNameFromFilePath(linkFile.Path())
diff --git a/rust/rust_test.go b/rust/rust_test.go
index b3bbddb..04de48b 100644
--- a/rust/rust_test.go
+++ b/rust/rust_test.go
@@ -233,6 +233,7 @@
":my_generator",
":libbindings",
],
+ rlibs: ["libbindings"],
}
rust_proc_macro {
name: "libprocmacro",
@@ -241,6 +242,7 @@
":my_generator",
":libbindings",
],
+ rlibs: ["libbindings"],
crate_name: "procmacro",
}
rust_library {
@@ -248,7 +250,9 @@
srcs: [
"foo.rs",
":my_generator",
- ":libbindings"],
+ ":libbindings",
+ ],
+ rlibs: ["libbindings"],
crate_name: "foo",
}
genrule {
@@ -260,7 +264,8 @@
}
rust_bindgen {
name: "libbindings",
- stem: "bindings",
+ crate_name: "bindings",
+ source_stem: "bindings",
host_supported: true,
wrapper_src: "src/any.h",
}
@@ -289,6 +294,21 @@
if !android.SuffixInList(libprocmacro.Implicits.Strings(), "/out/any.rs") {
t.Errorf("genrule generated source not included as implicit input for libprocmacro; Implicits %#v", libfoo.Implicits.Strings())
}
+
+ // 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) {
+ 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) {
+ 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) {
+ t.Errorf("bindgen dependency not detected as a rlib dependency (dependency missing from AndroidMkRlibs)")
+ }
+
}
func TestSourceProviderTargetMismatch(t *testing.T) {
@@ -305,7 +325,8 @@
}
rust_bindgen {
name: "libbindings",
- stem: "bindings",
+ crate_name: "bindings",
+ source_stem: "bindings",
wrapper_src: "src/any.h",
}
`)
diff --git a/rust/source_provider.go b/rust/source_provider.go
index da6147a..8bb7849 100644
--- a/rust/source_provider.go
+++ b/rust/source_provider.go
@@ -19,8 +19,13 @@
)
type SourceProviderProperties struct {
- // sets name of the output
- Stem *string `android:"arch_variant"`
+ // name for the generated source file. Defaults to module name (e.g. moduleNameFoo.rs is produced by default).
+ // Importantly, the inherited "stem" property for this module sets the output filename for the generated library
+ // variants only
+ Source_stem *string `android:"arch_variant"`
+
+ // crate name, used for the library variant of this source provider. See additional details in rust_library.
+ Crate_name string `android:"arch_variant"`
}
type baseSourceProvider struct {
@@ -28,6 +33,7 @@
outputFile android.Path
subAndroidMkOnce map[subAndroidMkProvider]bool
+ subName string
}
var _ SourceProvider = (*baseSourceProvider)(nil)
@@ -37,6 +43,7 @@
Srcs() android.Paths
sourceProviderProps() []interface{}
sourceProviderDeps(ctx DepsContext, deps Deps) Deps
+ setSubName(subName string)
}
func (sp *baseSourceProvider) Srcs() android.Paths {
@@ -59,8 +66,8 @@
func (sp *baseSourceProvider) getStem(ctx android.ModuleContext) string {
stem := ctx.ModuleName()
- if String(sp.Properties.Stem) != "" {
- stem = String(sp.Properties.Stem)
+ if String(sp.Properties.Source_stem) != "" {
+ stem = String(sp.Properties.Source_stem)
}
return stem
}
@@ -68,3 +75,7 @@
func (sp *baseSourceProvider) sourceProviderDeps(ctx DepsContext, deps Deps) Deps {
return deps
}
+
+func (sp *baseSourceProvider) setSubName(subName string) {
+ sp.subName = subName
+}