Merge changes Icbbf176c,I52beadc8

* changes:
  rust: Add ref to generated sources (aidl, bindgen)
  rust: refactor projectGeneratorSingleton
This commit is contained in:
Thiébaud Weksteen
2020-09-30 08:21:36 +00:00
committed by Gerrit Code Review
3 changed files with 98 additions and 42 deletions

View File

@@ -30,16 +30,6 @@ import (
//
// $ SOONG_GEN_RUST_PROJECT=1 m nothing
func init() {
android.RegisterSingletonType("rust_project_generator", rustProjectGeneratorSingleton)
}
func rustProjectGeneratorSingleton() android.Singleton {
return &projectGeneratorSingleton{}
}
type projectGeneratorSingleton struct{}
const (
// Environment variables used to control the behavior of this singleton.
envVariableCollectRustDeps = "SOONG_GEN_RUST_PROJECT"
@@ -49,6 +39,7 @@ const (
// The format of rust-project.json is not yet finalized. A current description is available at:
// https://github.com/rust-analyzer/rust-analyzer/blob/master/docs/user/manual.adoc#non-cargo-based-projects
type rustProjectDep struct {
// The Crate attribute is the index of the dependency in the Crates array in rustProjectJson.
Crate int `json:"crate"`
Name string `json:"name"`
}
@@ -71,12 +62,50 @@ type crateInfo struct {
Deps map[string]int
}
func mergeDependencies(ctx android.SingletonContext, project *rustProjectJson,
knownCrates map[string]crateInfo, module android.Module,
crate *rustProjectCrate, deps map[string]int) {
type projectGeneratorSingleton struct {
project rustProjectJson
knownCrates map[string]crateInfo
}
func rustProjectGeneratorSingleton() android.Singleton {
return &projectGeneratorSingleton{}
}
func init() {
android.RegisterSingletonType("rust_project_generator", rustProjectGeneratorSingleton)
}
// librarySource finds the main source file (.rs) for a crate.
func librarySource(ctx android.SingletonContext, rModule *Module, rustLib *libraryDecorator) (string, bool) {
srcs := rustLib.baseCompiler.Properties.Srcs
if len(srcs) != 0 {
return path.Join(ctx.ModuleDir(rModule), srcs[0]), true
}
if !rustLib.source() {
return "", false
}
// It is a SourceProvider module. If this module is host only, uses the variation for the host.
// Otherwise, use the variation for the primary target.
switch rModule.hod {
case android.HostSupported:
case android.HostSupportedNoCross:
if rModule.Target().String() != ctx.Config().BuildOSTarget.String() {
return "", false
}
default:
if rModule.Target().String() != ctx.Config().Targets[android.Android][0].String() {
return "", false
}
}
src := rustLib.sourceProvider.Srcs()[0]
return src.String(), true
}
func (singleton *projectGeneratorSingleton) mergeDependencies(ctx android.SingletonContext,
module android.Module, crate *rustProjectCrate, deps map[string]int) {
ctx.VisitDirectDeps(module, func(child android.Module) {
childId, childCrateName, ok := appendLibraryAndDeps(ctx, project, knownCrates, child)
childId, childCrateName, ok := singleton.appendLibraryAndDeps(ctx, child)
if !ok {
return
}
@@ -88,12 +117,10 @@ func mergeDependencies(ctx android.SingletonContext, project *rustProjectJson,
})
}
// appendLibraryAndDeps creates a rustProjectCrate for the module argument and
// appends it to the rustProjectJson struct. It visits the dependencies of the
// module depth-first. If the current module is already in knownCrates, its
// dependencies are merged. Returns a tuple (id, crate_name, ok).
func appendLibraryAndDeps(ctx android.SingletonContext, project *rustProjectJson,
knownCrates map[string]crateInfo, module android.Module) (int, string, bool) {
// appendLibraryAndDeps creates a rustProjectCrate for the module argument and appends it to singleton.project.
// It visits the dependencies of the module depth-first so the dependency ID can be added to the current module. If the
// current module is already in singleton.knownCrates, its dependencies are merged. Returns a tuple (id, crate_name, ok).
func (singleton *projectGeneratorSingleton) appendLibraryAndDeps(ctx android.SingletonContext, module android.Module) (int, string, bool) {
rModule, ok := module.(*Module)
if !ok {
return 0, "", false
@@ -107,46 +134,45 @@ func appendLibraryAndDeps(ctx android.SingletonContext, project *rustProjectJson
}
moduleName := ctx.ModuleName(module)
crateName := rModule.CrateName()
if cInfo, ok := knownCrates[moduleName]; ok {
if cInfo, ok := singleton.knownCrates[moduleName]; ok {
// We have seen this crate already; merge any new dependencies.
crate := project.Crates[cInfo.ID]
mergeDependencies(ctx, project, knownCrates, module, &crate, cInfo.Deps)
project.Crates[cInfo.ID] = crate
crate := singleton.project.Crates[cInfo.ID]
singleton.mergeDependencies(ctx, module, &crate, cInfo.Deps)
singleton.project.Crates[cInfo.ID] = crate
return cInfo.ID, crateName, true
}
crate := rustProjectCrate{Deps: make([]rustProjectDep, 0), Cfgs: make([]string, 0)}
srcs := rustLib.baseCompiler.Properties.Srcs
if len(srcs) == 0 {
rootModule, ok := librarySource(ctx, rModule, rustLib)
if !ok {
return 0, "", false
}
crate.RootModule = path.Join(ctx.ModuleDir(rModule), srcs[0])
crate.RootModule = rootModule
crate.Edition = rustLib.baseCompiler.edition()
deps := make(map[string]int)
mergeDependencies(ctx, project, knownCrates, module, &crate, deps)
singleton.mergeDependencies(ctx, module, &crate, deps)
id := len(project.Crates)
knownCrates[moduleName] = crateInfo{ID: id, Deps: deps}
project.Crates = append(project.Crates, crate)
id := len(singleton.project.Crates)
singleton.knownCrates[moduleName] = crateInfo{ID: id, Deps: deps}
singleton.project.Crates = append(singleton.project.Crates, crate)
// rust-analyzer requires that all crates belong to at least one root:
// https://github.com/rust-analyzer/rust-analyzer/issues/4735.
project.Roots = append(project.Roots, path.Dir(crate.RootModule))
singleton.project.Roots = append(singleton.project.Roots, path.Dir(crate.RootModule))
return id, crateName, true
}
func (r *projectGeneratorSingleton) GenerateBuildActions(ctx android.SingletonContext) {
func (singleton *projectGeneratorSingleton) GenerateBuildActions(ctx android.SingletonContext) {
if !ctx.Config().IsEnvTrue(envVariableCollectRustDeps) {
return
}
project := rustProjectJson{}
knownCrates := make(map[string]crateInfo)
singleton.knownCrates = make(map[string]crateInfo)
ctx.VisitAllModules(func(module android.Module) {
appendLibraryAndDeps(ctx, &project, knownCrates, module)
singleton.appendLibraryAndDeps(ctx, module)
})
path := android.PathForOutput(ctx, rustProjectJsonFileName)
err := createJsonFile(project, path)
err := createJsonFile(singleton.project, path)
if err != nil {
ctx.Errorf(err.Error())
}

View File

@@ -18,6 +18,7 @@ import (
"encoding/json"
"io/ioutil"
"path/filepath"
"strings"
"testing"
"android/soong/android"
@@ -100,22 +101,50 @@ func TestProjectJsonBindGen(t *testing.T) {
rust_library {
name: "liba",
srcs: ["src/lib.rs"],
rlibs: ["libbindings"],
rlibs: ["libbindings1"],
crate_name: "a"
}
rust_bindgen {
name: "libbindings",
crate_name: "bindings",
source_stem: "bindings",
name: "libbindings1",
crate_name: "bindings1",
source_stem: "bindings1",
host_supported: true,
wrapper_src: "src/any.h",
}
rust_library_host {
name: "libb",
srcs: ["src/lib.rs"],
rustlibs: ["libbindings2"],
crate_name: "b"
}
rust_bindgen_host {
name: "libbindings2",
crate_name: "bindings2",
source_stem: "bindings2",
wrapper_src: "src/any.h",
}
` + GatherRequiredDepsForTest()
fs := map[string][]byte{
"src/lib.rs": nil,
}
jsonContent := testProjectJson(t, bp, fs)
validateJsonCrates(t, jsonContent)
crates := validateJsonCrates(t, jsonContent)
for _, c := range crates {
crate, ok := c.(map[string]interface{})
if !ok {
t.Fatalf("Unexpected type for crate: %v", c)
}
rootModule, ok := crate["root_module"].(string)
if !ok {
t.Fatalf("Unexpected type for root_module: %v", crate["root_module"])
}
if strings.Contains(rootModule, "libbindings1") && !strings.Contains(rootModule, "android_arm64") {
t.Errorf("The source for libbindings1 does not contain android_arm64, got %v", rootModule)
}
if strings.Contains(rootModule, "libbindings2") && !strings.Contains(rootModule, "linux_glibc") {
t.Errorf("The source for libbindings2 does not contain linux_glibc, got %v", rootModule)
}
}
}
func TestProjectJsonMultiVersion(t *testing.T) {

View File

@@ -117,6 +117,7 @@ func CreateTestContext() *android.TestContext {
ctx.RegisterModuleType("rust_binary", RustBinaryFactory)
ctx.RegisterModuleType("rust_binary_host", RustBinaryHostFactory)
ctx.RegisterModuleType("rust_bindgen", RustBindgenFactory)
ctx.RegisterModuleType("rust_bindgen_host", RustBindgenHostFactory)
ctx.RegisterModuleType("rust_test", RustTestFactory)
ctx.RegisterModuleType("rust_test_host", RustTestHostFactory)
ctx.RegisterModuleType("rust_library", RustLibraryFactory)