[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
This commit is contained in:
Ivan Lozano
2020-07-31 13:40:31 -04:00
parent d118b1c2b7
commit 26ecd6c597
9 changed files with 134 additions and 36 deletions

View File

@@ -55,7 +55,6 @@ func (mod *Module) AndroidMk() android.AndroidMkData {
ret := android.AndroidMkData{ ret := android.AndroidMkData{
OutputFile: mod.outputFile, OutputFile: mod.outputFile,
Include: "$(BUILD_SYSTEM)/soong_rust_prebuilt.mk", Include: "$(BUILD_SYSTEM)/soong_rust_prebuilt.mk",
SubName: mod.subName,
Extra: []android.AndroidMkExtraFunc{ Extra: []android.AndroidMkExtraFunc{
func(w io.Writer, outputFile android.Path) { func(w io.Writer, outputFile android.Path) {
if len(mod.Properties.AndroidMkRlibs) > 0 { if len(mod.Properties.AndroidMkRlibs) > 0 {
@@ -76,9 +75,11 @@ func (mod *Module) AndroidMk() android.AndroidMkData {
}, },
}, },
} }
if mod.compiler != nil {
if mod.compiler != nil && !mod.compiler.Disabled() {
mod.subAndroidMk(&ret, mod.compiler) mod.subAndroidMk(&ret, mod.compiler)
} else if mod.sourceProvider != nil { } else if mod.sourceProvider != nil {
// If the compiler is disabled, this is a SourceProvider.
mod.subAndroidMk(&ret, mod.sourceProvider) mod.subAndroidMk(&ret, mod.sourceProvider)
} }
ret.SubName += mod.Properties.SubName ret.SubName += mod.Properties.SubName
@@ -162,6 +163,7 @@ func (sourceProvider *baseSourceProvider) AndroidMk(ctx AndroidMkContext, ret *a
outFile := sourceProvider.outputFile outFile := sourceProvider.outputFile
ret.Class = "ETC" ret.Class = "ETC"
ret.OutputFile = android.OptionalPathForPath(outFile) ret.OutputFile = android.OptionalPathForPath(outFile)
ret.SubName += sourceProvider.subName
ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) { ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) {
_, file := filepath.Split(outFile.String()) _, file := filepath.Split(outFile.String())
stem, suffix, _ := android.SplitFileExt(file) stem, suffix, _ := android.SplitFileExt(file)

View File

@@ -61,7 +61,7 @@ type BindgenProperties struct {
Wrapper_src *string `android:"path,arch_variant"` Wrapper_src *string `android:"path,arch_variant"`
// list of bindgen-specific flags and options // 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. // list of clang flags required to correctly interpret the headers.
Cflags []string `android:"arch_variant"` Cflags []string `android:"arch_variant"`
@@ -121,7 +121,7 @@ func (b *bindgenDecorator) generateSource(ctx android.ModuleContext, deps PathDe
} }
bindgenFlags := defaultBindgenFlags 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) wrapperFile := android.OptionalPathForModuleSrc(ctx, b.Properties.Wrapper_src)
if !wrapperFile.Valid() { if !wrapperFile.Valid() {
@@ -170,7 +170,13 @@ func NewRustBindgen(hod android.HostOrDeviceSupported) (*Module, *bindgenDecorat
baseSourceProvider: NewSourceProvider(), baseSourceProvider: NewSourceProvider(),
Properties: BindgenProperties{}, Properties: BindgenProperties{},
} }
_, library := NewRustLibrary(hod)
library.BuildOnlyRust()
library.sourceProvider = bindgen
module.sourceProvider = bindgen module.sourceProvider = bindgen
module.compiler = library
return module, bindgen return module, bindgen
} }

View File

@@ -24,8 +24,10 @@ func TestRustBindgen(t *testing.T) {
rust_bindgen { rust_bindgen {
name: "libbindgen", name: "libbindgen",
wrapper_src: "src/any.h", wrapper_src: "src/any.h",
stem: "bindings", crate_name: "bindgen",
flags: ["--bindgen-flag"], stem: "libbindgen",
source_stem: "bindings",
bindgen_flags: ["--bindgen-flag"],
cflags: ["--clang-flag"], cflags: ["--clang-flag"],
shared_libs: ["libfoo_shared"], shared_libs: ["libfoo_shared"],
static_libs: ["libfoo_static"], static_libs: ["libfoo_static"],
@@ -38,7 +40,6 @@ func TestRustBindgen(t *testing.T) {
name: "libfoo_static", name: "libfoo_static",
export_include_dirs: ["static_include"], export_include_dirs: ["static_include"],
} }
`) `)
libbindgen := ctx.ModuleForTests("libbindgen", "android_arm64_armv8-a").Output("bindings.rs") libbindgen := ctx.ModuleForTests("libbindgen", "android_arm64_armv8-a").Output("bindings.rs")
if !strings.Contains(libbindgen.Args["flags"], "--bindgen-flag") { if !strings.Contains(libbindgen.Args["flags"], "--bindgen-flag") {

View File

@@ -28,12 +28,14 @@ func TestSourceProviderCollision(t *testing.T) {
} }
rust_bindgen { rust_bindgen {
name: "libbindings1", name: "libbindings1",
stem: "bindings", source_stem: "bindings",
crate_name: "bindings1",
wrapper_src: "src/any.h", wrapper_src: "src/any.h",
} }
rust_bindgen { rust_bindgen {
name: "libbindings2", name: "libbindings2",
stem: "bindings", source_stem: "bindings",
crate_name: "bindings2",
wrapper_src: "src/any.h", wrapper_src: "src/any.h",
} }
`) `)

View File

@@ -81,7 +81,10 @@ type BaseCompilerProperties struct {
// list of C static library dependencies // list of C static library dependencies
Static_libs []string `android:"arch_variant"` 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"` Crate_name string `android:"arch_variant"`
// list of features to enable for this crate // list of features to enable for this crate
@@ -120,6 +123,14 @@ type baseCompiler struct {
distFile android.OptionalPath 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 { func (compiler *baseCompiler) coverageOutputZipPath() android.OptionalPath {
panic("baseCompiler does not implement coverageOutputZipPath()") panic("baseCompiler does not implement coverageOutputZipPath()")
} }

View File

@@ -69,6 +69,10 @@ type LibraryMutatedProperties struct {
VariantIsShared bool `blueprint:"mutated"` VariantIsShared bool `blueprint:"mutated"`
// This variant is a static library // This variant is a static library
VariantIsStatic bool `blueprint:"mutated"` 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 { type libraryDecorator struct {
@@ -78,6 +82,7 @@ type libraryDecorator struct {
Properties LibraryCompilerProperties Properties LibraryCompilerProperties
MutatedProperties LibraryMutatedProperties MutatedProperties LibraryMutatedProperties
includeDirs android.Paths includeDirs android.Paths
sourceProvider SourceProvider
} }
type libraryInterface interface { type libraryInterface interface {
@@ -367,8 +372,13 @@ func (library *libraryDecorator) compilerFlags(ctx ModuleContext, flags Flags) F
func (library *libraryDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) android.Path { func (library *libraryDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) android.Path {
var outputFile android.WritablePath 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...) flags.RustFlags = append(flags.RustFlags, deps.depFlags...)
@@ -430,6 +440,14 @@ func (library *libraryDecorator) getStem(ctx ModuleContext) string {
return stem + String(library.baseCompiler.Properties.Suffix) 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_]+") var validCrateName = regexp.MustCompile("[^a-zA-Z0-9_]+")
func validateLibraryStem(ctx BaseModuleContext, filename string, crate_name string) { func validateLibraryStem(ctx BaseModuleContext, filename string, crate_name string) {
@@ -455,12 +473,23 @@ func LibraryMutator(mctx android.BottomUpMutatorContext) {
switch library := m.compiler.(type) { switch library := m.compiler.(type) {
case libraryInterface: case libraryInterface:
if library.buildRlib() && library.buildDylib() { 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) rlib := modules[0].(*Module)
dylib := modules[1].(*Module) dylib := modules[1].(*Module)
rlib.compiler.(libraryInterface).setRlib() rlib.compiler.(libraryInterface).setRlib()
dylib.compiler.(libraryInterface).setDylib() 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() { } else if library.buildRlib() {
modules := mctx.CreateLocalVariations("rlib") modules := mctx.CreateLocalVariations("rlib")
modules[0].(*Module).compiler.(libraryInterface).setRlib() modules[0].(*Module).compiler.(libraryInterface).setRlib()
@@ -468,6 +497,11 @@ func LibraryMutator(mctx android.BottomUpMutatorContext) {
modules := mctx.CreateLocalVariations("dylib") modules := mctx.CreateLocalVariations("dylib")
modules[0].(*Module).compiler.(libraryInterface).setDylib() modules[0].(*Module).compiler.(libraryInterface).setDylib()
} }
if m.sourceProvider != nil {
// Alias the non-library variant to the empty-string variant.
mctx.AliasVariation("")
}
} }
} }
} }

View File

@@ -64,6 +64,7 @@ type BaseProperties struct {
AndroidMkStaticLibs []string AndroidMkStaticLibs []string
SubName string `blueprint:"mutated"` SubName string `blueprint:"mutated"`
PreventInstall bool PreventInstall bool
HideFromMake bool HideFromMake bool
} }
@@ -83,9 +84,9 @@ type Module struct {
cachedToolchain config.Toolchain cachedToolchain config.Toolchain
sourceProvider SourceProvider sourceProvider SourceProvider
subAndroidMkOnce map[subAndroidMkProvider]bool subAndroidMkOnce map[subAndroidMkProvider]bool
outputFile android.OptionalPath
subName string outputFile android.OptionalPath
generatedFile android.OptionalPath
} }
func (mod *Module) OutputFiles(tag string) (android.Paths, error) { func (mod *Module) OutputFiles(tag string) (android.Paths, error) {
@@ -285,6 +286,9 @@ type compiler interface {
relativeInstallPath() string relativeInstallPath() string
nativeCoverage() bool nativeCoverage() bool
Disabled() bool
SetDisabled()
} }
type exportedFlagsProducer interface { type exportedFlagsProducer interface {
@@ -667,16 +671,21 @@ func (mod *Module) GenerateAndroidBuildActions(actx android.ModuleContext) {
flags, deps = mod.clippy.flags(ctx, flags, deps) 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) outputFile := mod.compiler.compile(ctx, flags, deps)
mod.outputFile = android.OptionalPathForPath(outputFile) mod.outputFile = android.OptionalPathForPath(outputFile)
if !mod.Properties.PreventInstall { if mod.outputFile.Valid() && !mod.Properties.PreventInstall {
mod.compiler.install(ctx, mod.outputFile.Path()) 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 @@ func (mod *Module) deps(ctx DepsContext) Deps {
if mod.compiler != nil { if mod.compiler != nil {
deps = mod.compiler.compilerDeps(ctx, deps) deps = mod.compiler.compilerDeps(ctx, deps)
} else if mod.sourceProvider != nil { }
if mod.sourceProvider != nil {
deps = mod.sourceProvider.sourceProviderDeps(ctx, deps) deps = mod.sourceProvider.sourceProviderDeps(ctx, deps)
} }
@@ -755,11 +765,6 @@ func (mod *Module) depsToPaths(ctx android.ModuleContext) PathDeps {
if rustDep, ok := dep.(*Module); ok && !rustDep.CcLibraryInterface() { if rustDep, ok := dep.(*Module); ok && !rustDep.CcLibraryInterface() {
//Handle Rust Modules //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 { switch depTag {
case dylibDepTag: case dylibDepTag:
dylib, ok := rustDep.compiler.(libraryInterface) dylib, ok := rustDep.compiler.(libraryInterface)
@@ -808,6 +813,12 @@ func (mod *Module) depsToPaths(ctx android.ModuleContext) PathDeps {
} }
if depTag == dylibDepTag || depTag == rlibDepTag || depTag == procMacroDepTag { 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()) linkDir := linkPathFromFilePath(linkFile.Path())
if lib, ok := mod.compiler.(exportedFlagsProducer); ok { if lib, ok := mod.compiler.(exportedFlagsProducer); ok {
lib.exportLinkDirs(linkDir) lib.exportLinkDirs(linkDir)
@@ -826,7 +837,6 @@ func (mod *Module) depsToPaths(ctx android.ModuleContext) PathDeps {
return return
} }
} }
linkFile := ccDep.OutputFile() linkFile := ccDep.OutputFile()
linkPath := linkPathFromFilePath(linkFile.Path()) linkPath := linkPathFromFilePath(linkFile.Path())
libName := libNameFromFilePath(linkFile.Path()) libName := libNameFromFilePath(linkFile.Path())

View File

@@ -233,6 +233,7 @@ func TestSourceProviderDeps(t *testing.T) {
":my_generator", ":my_generator",
":libbindings", ":libbindings",
], ],
rlibs: ["libbindings"],
} }
rust_proc_macro { rust_proc_macro {
name: "libprocmacro", name: "libprocmacro",
@@ -241,6 +242,7 @@ func TestSourceProviderDeps(t *testing.T) {
":my_generator", ":my_generator",
":libbindings", ":libbindings",
], ],
rlibs: ["libbindings"],
crate_name: "procmacro", crate_name: "procmacro",
} }
rust_library { rust_library {
@@ -248,7 +250,9 @@ func TestSourceProviderDeps(t *testing.T) {
srcs: [ srcs: [
"foo.rs", "foo.rs",
":my_generator", ":my_generator",
":libbindings"], ":libbindings",
],
rlibs: ["libbindings"],
crate_name: "foo", crate_name: "foo",
} }
genrule { genrule {
@@ -260,7 +264,8 @@ func TestSourceProviderDeps(t *testing.T) {
} }
rust_bindgen { rust_bindgen {
name: "libbindings", name: "libbindings",
stem: "bindings", crate_name: "bindings",
source_stem: "bindings",
host_supported: true, host_supported: true,
wrapper_src: "src/any.h", wrapper_src: "src/any.h",
} }
@@ -289,6 +294,21 @@ func TestSourceProviderDeps(t *testing.T) {
if !android.SuffixInList(libprocmacro.Implicits.Strings(), "/out/any.rs") { 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()) 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) { func TestSourceProviderTargetMismatch(t *testing.T) {
@@ -305,7 +325,8 @@ func TestSourceProviderTargetMismatch(t *testing.T) {
} }
rust_bindgen { rust_bindgen {
name: "libbindings", name: "libbindings",
stem: "bindings", crate_name: "bindings",
source_stem: "bindings",
wrapper_src: "src/any.h", wrapper_src: "src/any.h",
} }
`) `)

View File

@@ -19,8 +19,13 @@ import (
) )
type SourceProviderProperties struct { type SourceProviderProperties struct {
// sets name of the output // name for the generated source file. Defaults to module name (e.g. moduleNameFoo.rs is produced by default).
Stem *string `android:"arch_variant"` // 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 { type baseSourceProvider struct {
@@ -28,6 +33,7 @@ type baseSourceProvider struct {
outputFile android.Path outputFile android.Path
subAndroidMkOnce map[subAndroidMkProvider]bool subAndroidMkOnce map[subAndroidMkProvider]bool
subName string
} }
var _ SourceProvider = (*baseSourceProvider)(nil) var _ SourceProvider = (*baseSourceProvider)(nil)
@@ -37,6 +43,7 @@ type SourceProvider interface {
Srcs() android.Paths Srcs() android.Paths
sourceProviderProps() []interface{} sourceProviderProps() []interface{}
sourceProviderDeps(ctx DepsContext, deps Deps) Deps sourceProviderDeps(ctx DepsContext, deps Deps) Deps
setSubName(subName string)
} }
func (sp *baseSourceProvider) Srcs() android.Paths { func (sp *baseSourceProvider) Srcs() android.Paths {
@@ -59,8 +66,8 @@ func NewSourceProvider() *baseSourceProvider {
func (sp *baseSourceProvider) getStem(ctx android.ModuleContext) string { func (sp *baseSourceProvider) getStem(ctx android.ModuleContext) string {
stem := ctx.ModuleName() stem := ctx.ModuleName()
if String(sp.Properties.Stem) != "" { if String(sp.Properties.Source_stem) != "" {
stem = String(sp.Properties.Stem) stem = String(sp.Properties.Source_stem)
} }
return stem return stem
} }
@@ -68,3 +75,7 @@ func (sp *baseSourceProvider) getStem(ctx android.ModuleContext) string {
func (sp *baseSourceProvider) sourceProviderDeps(ctx DepsContext, deps Deps) Deps { func (sp *baseSourceProvider) sourceProviderDeps(ctx DepsContext, deps Deps) Deps {
return deps return deps
} }
func (sp *baseSourceProvider) setSubName(subName string) {
sp.subName = subName
}