Merge changes from topic "rust-made-to-order-staticlibs" into main

* changes:
  rust: made-to-order rust staticlibs
  rust: refactored transformSrctoCrate
This commit is contained in:
Ivan Lozano 2024-05-17 12:40:36 +00:00 committed by Gerrit Code Review
commit e8fcd37775
23 changed files with 832 additions and 241 deletions

View file

@ -302,6 +302,24 @@ func RemoveFromList(s string, list []string) (bool, []string) {
return removed, result
}
// FirstUniqueFunc returns all unique elements of a slice, keeping the first copy of
// each. It does not modify the input slice. The eq function should return true
// if two elements can be considered equal.
func FirstUniqueFunc[SortableList ~[]Sortable, Sortable any](list SortableList, eq func(a, b Sortable) bool) SortableList {
k := 0
outer:
for i := 0; i < len(list); i++ {
for j := 0; j < k; j++ {
if eq(list[i], list[j]) {
continue outer
}
}
list[k] = list[i]
k++
}
return list[:k]
}
// FirstUniqueStrings returns all unique elements of a slice of strings, keeping the first copy of
// each. It does not modify the input slice.
func FirstUniqueStrings(list []string) []string {

View file

@ -699,7 +699,12 @@ var (
func addDependenciesForNativeModules(ctx android.BottomUpMutatorContext, nativeModules ApexNativeDependencies, target android.Target, imageVariation string) {
binVariations := target.Variations()
libVariations := append(target.Variations(), blueprint.Variation{Mutator: "link", Variation: "shared"})
rustLibVariations := append(target.Variations(), blueprint.Variation{Mutator: "rust_libraries", Variation: "dylib"})
rustLibVariations := append(
target.Variations(), []blueprint.Variation{
{Mutator: "rust_libraries", Variation: "dylib"},
{Mutator: "link", Variation: ""},
}...,
)
// Append "image" variation
binVariations = append(binVariations, blueprint.Variation{Mutator: "image", Variation: imageVariation})

View file

@ -18,6 +18,7 @@ import (
"path/filepath"
"android/soong/android"
"github.com/google/blueprint"
)
@ -425,6 +426,10 @@ func (binary *binaryDecorator) link(ctx ModuleContext,
validations = append(validations, objs.tidyDepFiles...)
linkerDeps = append(linkerDeps, flags.LdFlagsDeps...)
if generatedLib := generateRustStaticlib(ctx, deps.RustRlibDeps); generatedLib != nil {
deps.StaticLibs = append(deps.StaticLibs, generatedLib)
}
// Register link action.
transformObjToDynamicBinary(ctx, objs.objFiles, sharedLibs, deps.StaticLibs,
deps.LateStaticLibs, deps.WholeStaticLibs, linkerDeps, deps.CrtBegin, deps.CrtEnd, true,

View file

@ -19,6 +19,7 @@ package cc
// functions.
import (
"fmt"
"path/filepath"
"runtime"
"strconv"
@ -330,6 +331,15 @@ var (
CommandDeps: []string{"$cxxExtractor", "$kytheVnames"},
},
"cFlags")
// Function pointer for producting staticlibs from rlibs. Corresponds to
// rust.TransformRlibstoStaticlib(), initialized in soong-rust (rust/builder.go init())
//
// This is required since soong-rust depends on soong-cc, so soong-cc cannot depend on soong-rust
// without resulting in a circular dependency. Setting this function pointer in soong-rust allows
// soong-cc to call into this particular function.
TransformRlibstoStaticlib (func(ctx android.ModuleContext, mainSrc android.Path, deps []RustRlibDep,
outputFile android.WritablePath) android.Path) = nil
)
func PwdPrefix() string {
@ -778,6 +788,47 @@ func transformObjToStaticLib(ctx android.ModuleContext,
}
}
// Generate a Rust staticlib from a list of rlibDeps. Returns nil if TransformRlibstoStaticlib is nil or rlibDeps is empty.
func generateRustStaticlib(ctx android.ModuleContext, rlibDeps []RustRlibDep) android.Path {
if TransformRlibstoStaticlib == nil && len(rlibDeps) > 0 {
// This should only be reachable if a module defines static_rlibs and
// soong-rust hasn't been loaded alongside soong-cc (e.g. in soong-cc tests).
panic(fmt.Errorf("TransformRlibstoStaticlib is not set and static_rlibs is defined in %s", ctx.ModuleName()))
} else if len(rlibDeps) == 0 {
return nil
}
output := android.PathForModuleOut(ctx, "generated_rust_staticlib", "lib"+ctx.ModuleName()+"_rust_staticlib.a")
stemFile := output.ReplaceExtension(ctx, "rs")
crateNames := []string{}
// Collect crate names
for _, lib := range rlibDeps {
// Exclude libstd so this can support no_std builds.
if lib.CrateName != "libstd" {
crateNames = append(crateNames, lib.CrateName)
}
}
// Deduplicate any crateNames just to be safe
crateNames = android.FirstUniqueStrings(crateNames)
// Write the source file
android.WriteFileRule(ctx, stemFile, genRustStaticlibSrcFile(crateNames))
return TransformRlibstoStaticlib(ctx, stemFile, rlibDeps, output)
}
func genRustStaticlibSrcFile(crateNames []string) string {
lines := []string{
"// @Soong generated Source",
}
for _, crate := range crateNames {
lines = append(lines, fmt.Sprintf("extern crate %s;", crate))
}
return strings.Join(lines, "\n")
}
// Generate a rule for compiling multiple .o files, plus static libraries, whole static libraries,
// and shared libraries, to a shared library (.so) or dynamic executable
func transformObjToDynamicBinary(ctx android.ModuleContext,

View file

@ -100,6 +100,7 @@ type Deps struct {
StaticLibs, LateStaticLibs, WholeStaticLibs []string
HeaderLibs []string
RuntimeLibs []string
Rlibs []string
// UnexportedStaticLibs are static libraries that are also passed to -Wl,--exclude-libs= to
// prevent automatically exporting symbols.
@ -145,6 +146,17 @@ type Deps struct {
LlndkHeaderLibs []string
}
// A struct which to collect flags for rlib dependencies
type RustRlibDep struct {
LibPath android.Path // path to the rlib
LinkDirs []string // flags required for dependency (e.g. -L flags)
CrateName string // crateNames associated with rlibDeps
}
func EqRustRlibDeps(a RustRlibDep, b RustRlibDep) bool {
return a.LibPath == b.LibPath
}
// PathDeps is a struct containing file paths to dependencies of a module.
// It's constructed in depsToPath() by traversing the direct dependencies of the current module.
// It's used to construct flags for various build statements (such as for compiling and linking).
@ -157,6 +169,8 @@ type PathDeps struct {
SharedLibsDeps, EarlySharedLibsDeps, LateSharedLibsDeps android.Paths
// Paths to .a files
StaticLibs, LateStaticLibs, WholeStaticLibs android.Paths
// Paths and crateNames for RustStaticLib dependencies
RustRlibDeps []RustRlibDep
// Transitive static library dependencies of static libraries for use in ordering.
TranstiveStaticLibrariesForOrdering *android.DepSet[android.Path]
@ -185,6 +199,7 @@ type PathDeps struct {
ReexportedFlags []string
ReexportedGeneratedHeaders android.Paths
ReexportedDeps android.Paths
ReexportedRustRlibDeps []RustRlibDep
// Paths to crt*.o files
CrtBegin, CrtEnd android.Paths
@ -298,6 +313,7 @@ type BaseProperties struct {
AndroidMkSharedLibs []string `blueprint:"mutated"`
AndroidMkStaticLibs []string `blueprint:"mutated"`
AndroidMkRlibs []string `blueprint:"mutated"`
AndroidMkRuntimeLibs []string `blueprint:"mutated"`
AndroidMkWholeStaticLibs []string `blueprint:"mutated"`
AndroidMkHeaderLibs []string `blueprint:"mutated"`
@ -660,6 +676,7 @@ const (
headerLibraryDependency = iota
sharedLibraryDependency
staticLibraryDependency
rlibLibraryDependency
)
func (k libraryDependencyKind) String() string {
@ -670,6 +687,8 @@ func (k libraryDependencyKind) String() string {
return "sharedLibraryDependency"
case staticLibraryDependency:
return "staticLibraryDependency"
case rlibLibraryDependency:
return "rlibLibraryDependency"
default:
panic(fmt.Errorf("unknown libraryDependencyKind %d", k))
}
@ -747,6 +766,11 @@ func (d libraryDependencyTag) static() bool {
return d.Kind == staticLibraryDependency
}
// rlib returns true if the libraryDependencyTag is tagging an rlib dependency.
func (d libraryDependencyTag) rlib() bool {
return d.Kind == rlibLibraryDependency
}
func (d libraryDependencyTag) LicenseAnnotations() []android.LicenseAnnotation {
if d.shared() {
return []android.LicenseAnnotation{android.LicenseAnnotationSharedDependency}
@ -1114,6 +1138,14 @@ func (c *Module) RustLibraryInterface() bool {
return false
}
func (c *Module) CrateName() string {
panic(fmt.Errorf("CrateName called on non-Rust module: %q", c.BaseModuleName()))
}
func (c *Module) ExportedCrateLinkDirs() []string {
panic(fmt.Errorf("ExportedCrateLinkDirs called on non-Rust module: %q", c.BaseModuleName()))
}
func (c *Module) IsFuzzModule() bool {
if _, ok := c.compiler.(*fuzzBinary); ok {
return true
@ -2309,6 +2341,7 @@ func (c *Module) deps(ctx DepsContext) Deps {
deps.WholeStaticLibs = android.LastUniqueStrings(deps.WholeStaticLibs)
deps.StaticLibs = android.LastUniqueStrings(deps.StaticLibs)
deps.Rlibs = android.LastUniqueStrings(deps.Rlibs)
deps.LateStaticLibs = android.LastUniqueStrings(deps.LateStaticLibs)
deps.SharedLibs = android.LastUniqueStrings(deps.SharedLibs)
deps.LateSharedLibs = android.LastUniqueStrings(deps.LateSharedLibs)
@ -2616,6 +2649,15 @@ func (c *Module) DepsMutator(actx android.BottomUpMutatorContext) {
}, depTag, lib)
}
for _, lib := range deps.Rlibs {
depTag := libraryDependencyTag{Kind: rlibLibraryDependency}
actx.AddVariationDependencies([]blueprint.Variation{
{Mutator: "link", Variation: ""},
{Mutator: "rust_libraries", Variation: "rlib"},
{Mutator: "rust_stdlinkage", Variation: "rlib-std"},
}, depTag, lib)
}
// staticUnwinderDep is treated as staticDep for Q apexes
// so that native libraries/binaries are linked with static unwinder
// because Q libc doesn't have unwinder APIs
@ -3225,6 +3267,14 @@ func (c *Module) depsToPaths(ctx android.ModuleContext) PathDeps {
default:
panic(fmt.Errorf("unexpected library dependency order %d", libDepTag.Order))
}
case libDepTag.rlib():
rlibDep := RustRlibDep{LibPath: linkFile.Path(), CrateName: ccDep.CrateName(), LinkDirs: ccDep.ExportedCrateLinkDirs()}
depPaths.ReexportedRustRlibDeps = append(depPaths.ReexportedRustRlibDeps, rlibDep)
depPaths.RustRlibDeps = append(depPaths.RustRlibDeps, rlibDep)
depPaths.IncludeDirs = append(depPaths.IncludeDirs, depExporterInfo.IncludeDirs...)
depPaths.ReexportedDirs = append(depPaths.ReexportedDirs, depExporterInfo.IncludeDirs...)
case libDepTag.static():
staticLibraryInfo, isStaticLib := android.OtherModuleProvider(ctx, dep, StaticLibraryInfoProvider)
if !isStaticLib {
@ -3277,6 +3327,12 @@ func (c *Module) depsToPaths(ctx android.ModuleContext) PathDeps {
panic(fmt.Errorf("unexpected library dependency order %d", libDepTag.Order))
}
}
// We re-export the Rust static_rlibs so rlib dependencies don't need to be redeclared by cc_library_static dependents.
// E.g. libfoo (cc_library_static) depends on libfoo.ffi (a rust_ffi rlib), libbar depending on libfoo shouldn't have to also add libfoo.ffi to static_rlibs.
depPaths.ReexportedRustRlibDeps = append(depPaths.ReexportedRustRlibDeps, depExporterInfo.RustRlibDeps...)
depPaths.RustRlibDeps = append(depPaths.RustRlibDeps, depExporterInfo.RustRlibDeps...)
if libDepTag.unexportedSymbols {
depPaths.LdFlags = append(depPaths.LdFlags,
"-Wl,--exclude-libs="+staticLibraryInfo.StaticLibrary.Base())
@ -3329,6 +3385,12 @@ func (c *Module) depsToPaths(ctx android.ModuleContext) PathDeps {
depPaths.SystemIncludeDirs = append(depPaths.SystemIncludeDirs, depExporterInfo.SystemIncludeDirs...)
depPaths.GeneratedDeps = append(depPaths.GeneratedDeps, depExporterInfo.Deps...)
depPaths.Flags = append(depPaths.Flags, depExporterInfo.Flags...)
depPaths.RustRlibDeps = append(depPaths.RustRlibDeps, depExporterInfo.RustRlibDeps...)
// Only re-export RustRlibDeps for cc static libs
if c.static() {
depPaths.ReexportedRustRlibDeps = append(depPaths.ReexportedRustRlibDeps, depExporterInfo.RustRlibDeps...)
}
if libDepTag.reexportFlags {
reexportExporter(depExporterInfo)
@ -3401,11 +3463,14 @@ func (c *Module) depsToPaths(ctx android.ModuleContext) PathDeps {
depPaths.IncludeDirs = android.FirstUniquePaths(depPaths.IncludeDirs)
depPaths.SystemIncludeDirs = android.FirstUniquePaths(depPaths.SystemIncludeDirs)
depPaths.GeneratedDeps = android.FirstUniquePaths(depPaths.GeneratedDeps)
depPaths.RustRlibDeps = android.FirstUniqueFunc(depPaths.RustRlibDeps, EqRustRlibDeps)
depPaths.ReexportedDirs = android.FirstUniquePaths(depPaths.ReexportedDirs)
depPaths.ReexportedSystemDirs = android.FirstUniquePaths(depPaths.ReexportedSystemDirs)
depPaths.ReexportedFlags = android.FirstUniqueStrings(depPaths.ReexportedFlags)
depPaths.ReexportedDeps = android.FirstUniquePaths(depPaths.ReexportedDeps)
depPaths.ReexportedGeneratedHeaders = android.FirstUniquePaths(depPaths.ReexportedGeneratedHeaders)
depPaths.ReexportedRustRlibDeps = android.FirstUniqueFunc(depPaths.ReexportedRustRlibDeps, EqRustRlibDeps)
if c.sabi != nil {
c.sabi.Properties.ReexportedIncludes = android.FirstUniqueStrings(c.sabi.Properties.ReexportedIncludes)

View file

@ -792,6 +792,9 @@ type RustBindgenClangProperties struct {
// be added to the include path using -I
Local_include_dirs []string `android:"arch_variant,variant_prepend"`
// list of Rust static libraries.
Static_rlibs []string `android:"arch_variant,variant_prepend"`
// list of static libraries that provide headers for this binding.
Static_libs []string `android:"arch_variant,variant_prepend"`

View file

@ -597,7 +597,7 @@ func CollectAllSharedDependencies(ctx android.ModuleContext) (android.RuleBuilde
ctx.WalkDeps(func(child, parent android.Module) bool {
// If this is a Rust module which is not rust_ffi_shared, we still want to bundle any transitive
// shared dependencies (even for rust_ffi_static)
// shared dependencies (even for rust_ffi_rlib or rust_ffi_static)
if rustmod, ok := child.(LinkableInterface); ok && rustmod.RustLibraryInterface() && !rustmod.Shared() {
if recursed[ctx.OtherModuleName(child)] {
return false

View file

@ -274,11 +274,12 @@ func LibraryHostSharedFactory() android.Module {
type flagExporter struct {
Properties FlagExporterProperties
dirs android.Paths // Include directories to be included with -I
systemDirs android.Paths // System include directories to be included with -isystem
flags []string // Exported raw flags.
deps android.Paths
headers android.Paths
dirs android.Paths // Include directories to be included with -I
systemDirs android.Paths // System include directories to be included with -isystem
flags []string // Exported raw flags.
deps android.Paths
headers android.Paths
rustRlibDeps []RustRlibDep
}
// exportedIncludes returns the effective include paths for this module and
@ -339,6 +340,10 @@ func (f *flagExporter) reexportDeps(deps ...android.Path) {
f.deps = append(f.deps, deps...)
}
func (f *flagExporter) reexportRustStaticDeps(deps ...RustRlibDep) {
f.rustRlibDeps = append(f.rustRlibDeps, deps...)
}
// addExportedGeneratedHeaders does nothing but collects generated header files.
// This can be differ to exportedDeps which may contain phony files to minimize ninja.
func (f *flagExporter) addExportedGeneratedHeaders(headers ...android.Path) {
@ -356,6 +361,8 @@ func (f *flagExporter) setProvider(ctx android.ModuleContext) {
// Used sparingly, for extra files that need to be explicitly exported to dependers,
// or for phony files to minimize ninja.
Deps: f.deps,
// Used for exporting rlib deps of static libraries to dependents.
RustRlibDeps: f.rustRlibDeps,
// For exported generated headers, such as exported aidl headers, proto headers, or
// sysprop headers.
GeneratedHeaders: f.headers,
@ -1132,9 +1139,14 @@ func (library *libraryDecorator) linkShared(ctx ModuleContext,
linkerDeps = append(linkerDeps, deps.EarlySharedLibsDeps...)
linkerDeps = append(linkerDeps, deps.SharedLibsDeps...)
linkerDeps = append(linkerDeps, deps.LateSharedLibsDeps...)
if generatedLib := generateRustStaticlib(ctx, deps.RustRlibDeps); generatedLib != nil {
deps.StaticLibs = append(deps.StaticLibs, generatedLib)
}
transformObjToDynamicBinary(ctx, objs.objFiles, sharedLibs,
deps.StaticLibs, deps.LateStaticLibs, deps.WholeStaticLibs,
linkerDeps, deps.CrtBegin, deps.CrtEnd, false, builderFlags, outputFile, implicitOutputs, objs.tidyDepFiles)
deps.StaticLibs, deps.LateStaticLibs, deps.WholeStaticLibs, linkerDeps, deps.CrtBegin,
deps.CrtEnd, false, builderFlags, outputFile, implicitOutputs, objs.tidyDepFiles)
objs.coverageFiles = append(objs.coverageFiles, deps.StaticLibObjs.coverageFiles...)
objs.coverageFiles = append(objs.coverageFiles, deps.WholeStaticLibObjs.coverageFiles...)
@ -1598,6 +1610,10 @@ func (library *libraryDecorator) link(ctx ModuleContext,
library.reexportDeps(deps.ReexportedDeps...)
library.addExportedGeneratedHeaders(deps.ReexportedGeneratedHeaders...)
if library.static() && len(deps.ReexportedRustRlibDeps) > 0 {
library.reexportRustStaticDeps(deps.ReexportedRustRlibDeps...)
}
// Optionally export aidl headers.
if Bool(library.Properties.Aidl.Export_aidl_headers) {
if library.baseCompiler.hasAidl(deps) {
@ -2125,14 +2141,12 @@ func LinkageMutator(mctx android.BottomUpMutatorContext) {
// Header only
}
} else if library, ok := mctx.Module().(LinkableInterface); ok && library.CcLibraryInterface() {
} else if library, ok := mctx.Module().(LinkableInterface); ok && (library.CcLibraryInterface() || library.RustLibraryInterface()) {
// Non-cc.Modules may need an empty variant for their mutators.
variations := []string{}
if library.NonCcVariants() {
variations = append(variations, "")
}
isLLNDK := false
if m, ok := mctx.Module().(*Module); ok {
isLLNDK = m.IsLlndk()

View file

@ -73,6 +73,12 @@ type LinkableInterface interface {
// RustLibraryInterface returns true if this is a Rust library module
RustLibraryInterface() bool
// CrateName returns the crateName for a Rust library, panics if not a Rust library.
CrateName() string
// DepFlags returns a slice of Rustc string flags, panics if not a Rust library
ExportedCrateLinkDirs() []string
// BaseModuleName returns the android.ModuleBase.BaseModuleName() value for this module.
BaseModuleName() string
@ -380,6 +386,7 @@ type FlagExporterInfo struct {
SystemIncludeDirs android.Paths // System include directories to be included with -isystem
Flags []string // Exported raw flags.
Deps android.Paths
RustRlibDeps []RustRlibDep
GeneratedHeaders android.Paths
}

View file

@ -39,6 +39,9 @@ type BaseLinkerProperties struct {
// the dependency's .a file will be linked into this module using -Wl,--whole-archive.
Whole_static_libs []string `android:"arch_variant,variant_prepend"`
// list of Rust libs that should be statically linked into this module.
Static_rlibs []string `android:"arch_variant"`
// list of modules that should be statically linked into this module.
Static_libs []string `android:"arch_variant,variant_prepend"`
@ -116,10 +119,14 @@ type BaseLinkerProperties struct {
// product variant of the C/C++ module.
Static_libs []string
// list of ehader libs that only should be used to build vendor or product
// list of header libs that only should be used to build vendor or product
// variant of the C/C++ module.
Header_libs []string
// list of Rust libs that should be statically linked to build vendor or product
// variant.
Static_rlibs []string
// list of shared libs that should not be used to build vendor or
// product variant of the C/C++ module.
Exclude_shared_libs []string
@ -148,6 +155,10 @@ type BaseLinkerProperties struct {
// variant of the C/C++ module.
Static_libs []string
// list of Rust libs that should be statically linked to build the recovery
// variant.
Static_rlibs []string
// list of shared libs that should not be used to build
// the recovery variant of the C/C++ module.
Exclude_shared_libs []string
@ -165,10 +176,14 @@ type BaseLinkerProperties struct {
Exclude_runtime_libs []string
}
Ramdisk struct {
// list of static libs that only should be used to build the recovery
// list of static libs that only should be used to build the ramdisk
// variant of the C/C++ module.
Static_libs []string
// list of Rust libs that should be statically linked to build the ramdisk
// variant.
Static_rlibs []string
// list of shared libs that should not be used to build
// the ramdisk variant of the C/C++ module.
Exclude_shared_libs []string
@ -183,9 +198,13 @@ type BaseLinkerProperties struct {
}
Vendor_ramdisk struct {
// list of shared libs that should not be used to build
// the recovery variant of the C/C++ module.
// the vendor ramdisk variant of the C/C++ module.
Exclude_shared_libs []string
// list of Rust libs that should be statically linked to build the vendor ramdisk
// variant.
Static_rlibs []string
// list of static libs that should not be used to build
// the vendor ramdisk variant of the C/C++ module.
Exclude_static_libs []string
@ -201,6 +220,10 @@ type BaseLinkerProperties struct {
// variants.
Shared_libs []string
// list of Rust libs that should be statically linked to build the vendor ramdisk
// variant.
Static_rlibs []string
// list of ehader libs that only should be used to build platform variant of
// the C/C++ module.
Header_libs []string
@ -295,6 +318,7 @@ func (linker *baseLinker) linkerDeps(ctx DepsContext, deps Deps) Deps {
deps.WholeStaticLibs = append(deps.WholeStaticLibs, linker.Properties.Whole_static_libs...)
deps.HeaderLibs = append(deps.HeaderLibs, linker.Properties.Header_libs...)
deps.StaticLibs = append(deps.StaticLibs, linker.Properties.Static_libs...)
deps.Rlibs = append(deps.Rlibs, linker.Properties.Static_rlibs...)
deps.SharedLibs = append(deps.SharedLibs, linker.Properties.Shared_libs...)
deps.RuntimeLibs = append(deps.RuntimeLibs, linker.Properties.Runtime_libs...)
@ -338,6 +362,7 @@ func (linker *baseLinker) linkerDeps(ctx DepsContext, deps Deps) Deps {
deps.ReexportStaticLibHeaders = removeListFromList(deps.ReexportStaticLibHeaders, linker.Properties.Target.Vendor.Exclude_static_libs)
deps.WholeStaticLibs = removeListFromList(deps.WholeStaticLibs, linker.Properties.Target.Vendor.Exclude_static_libs)
deps.RuntimeLibs = removeListFromList(deps.RuntimeLibs, linker.Properties.Target.Vendor.Exclude_runtime_libs)
deps.Rlibs = append(deps.Rlibs, linker.Properties.Target.Vendor.Static_rlibs...)
}
if ctx.inProduct() {
@ -351,6 +376,7 @@ func (linker *baseLinker) linkerDeps(ctx DepsContext, deps Deps) Deps {
deps.ReexportStaticLibHeaders = removeListFromList(deps.ReexportStaticLibHeaders, linker.Properties.Target.Product.Exclude_static_libs)
deps.WholeStaticLibs = removeListFromList(deps.WholeStaticLibs, linker.Properties.Target.Product.Exclude_static_libs)
deps.RuntimeLibs = removeListFromList(deps.RuntimeLibs, linker.Properties.Target.Product.Exclude_runtime_libs)
deps.Rlibs = append(deps.Rlibs, linker.Properties.Target.Product.Static_rlibs...)
}
if ctx.inRecovery() {
@ -364,6 +390,7 @@ func (linker *baseLinker) linkerDeps(ctx DepsContext, deps Deps) Deps {
deps.ReexportStaticLibHeaders = removeListFromList(deps.ReexportStaticLibHeaders, linker.Properties.Target.Recovery.Exclude_static_libs)
deps.WholeStaticLibs = removeListFromList(deps.WholeStaticLibs, linker.Properties.Target.Recovery.Exclude_static_libs)
deps.RuntimeLibs = removeListFromList(deps.RuntimeLibs, linker.Properties.Target.Recovery.Exclude_runtime_libs)
deps.Rlibs = append(deps.Rlibs, linker.Properties.Target.Recovery.Static_rlibs...)
}
if ctx.inRamdisk() {
@ -374,6 +401,7 @@ func (linker *baseLinker) linkerDeps(ctx DepsContext, deps Deps) Deps {
deps.ReexportStaticLibHeaders = removeListFromList(deps.ReexportStaticLibHeaders, linker.Properties.Target.Ramdisk.Exclude_static_libs)
deps.WholeStaticLibs = removeListFromList(deps.WholeStaticLibs, linker.Properties.Target.Ramdisk.Exclude_static_libs)
deps.RuntimeLibs = removeListFromList(deps.RuntimeLibs, linker.Properties.Target.Ramdisk.Exclude_runtime_libs)
deps.Rlibs = append(deps.Rlibs, linker.Properties.Target.Ramdisk.Static_rlibs...)
}
if ctx.inVendorRamdisk() {
@ -383,6 +411,7 @@ func (linker *baseLinker) linkerDeps(ctx DepsContext, deps Deps) Deps {
deps.ReexportStaticLibHeaders = removeListFromList(deps.ReexportStaticLibHeaders, linker.Properties.Target.Vendor_ramdisk.Exclude_static_libs)
deps.WholeStaticLibs = removeListFromList(deps.WholeStaticLibs, linker.Properties.Target.Vendor_ramdisk.Exclude_static_libs)
deps.RuntimeLibs = removeListFromList(deps.RuntimeLibs, linker.Properties.Target.Vendor_ramdisk.Exclude_runtime_libs)
deps.Rlibs = append(deps.Rlibs, linker.Properties.Target.Vendor_ramdisk.Static_rlibs...)
}
if !ctx.useSdk() {

View file

@ -300,6 +300,7 @@ func commonDefaultModules() string {
system_shared_libs: [],
stl: "none",
vendor_available: true,
vendor_ramdisk_available: true,
product_available: true,
recovery_available: true,
host_supported: true,

View file

@ -21,6 +21,7 @@ import (
"github.com/google/blueprint"
"android/soong/android"
"android/soong/cc"
"android/soong/rust/config"
)
@ -118,42 +119,119 @@ type buildOutput struct {
func init() {
pctx.HostBinToolVariable("SoongZipCmd", "soong_zip")
cc.TransformRlibstoStaticlib = TransformRlibstoStaticlib
}
type transformProperties struct {
crateName string
targetTriple string
is64Bit bool
bootstrap bool
inRecovery bool
inRamdisk bool
inVendorRamdisk bool
cargoOutDir android.OptionalPath
synthetic bool
crateType string
}
// Populates a standard transformProperties struct for Rust modules
func getTransformProperties(ctx ModuleContext, crateType string) transformProperties {
module := ctx.RustModule()
return transformProperties{
crateName: module.CrateName(),
is64Bit: ctx.toolchain().Is64Bit(),
targetTriple: ctx.toolchain().RustTriple(),
bootstrap: module.Bootstrap(),
inRecovery: module.InRecovery(),
inRamdisk: module.InRamdisk(),
inVendorRamdisk: module.InVendorRamdisk(),
cargoOutDir: module.compiler.cargoOutDir(),
// crateType indicates what type of crate to build
crateType: crateType,
// synthetic indicates whether this is an actual Rust module or not
synthetic: false,
}
}
func TransformSrcToBinary(ctx ModuleContext, mainSrc android.Path, deps PathDeps, flags Flags,
outputFile android.WritablePath) buildOutput {
flags.GlobalRustFlags = append(flags.GlobalRustFlags, "-C lto=thin")
return transformSrctoCrate(ctx, mainSrc, deps, flags, outputFile, "bin")
return transformSrctoCrate(ctx, mainSrc, deps, flags, outputFile, getTransformProperties(ctx, "bin"))
}
func TransformSrctoRlib(ctx ModuleContext, mainSrc android.Path, deps PathDeps, flags Flags,
outputFile android.WritablePath) buildOutput {
return transformSrctoCrate(ctx, mainSrc, deps, flags, outputFile, "rlib")
return transformSrctoCrate(ctx, mainSrc, deps, flags, outputFile, getTransformProperties(ctx, "rlib"))
}
func TransformRlibstoStaticlib(ctx android.ModuleContext, mainSrc android.Path, deps []cc.RustRlibDep,
outputFile android.WritablePath) android.Path {
var rustPathDeps PathDeps
var rustFlags Flags
for _, rlibDep := range deps {
rustPathDeps.RLibs = append(rustPathDeps.RLibs, RustLibrary{Path: rlibDep.LibPath, CrateName: rlibDep.CrateName})
rustPathDeps.linkDirs = append(rustPathDeps.linkDirs, rlibDep.LinkDirs...)
}
ccModule := ctx.(cc.ModuleContext).Module().(*cc.Module)
toolchain := config.FindToolchain(ctx.Os(), ctx.Arch())
t := transformProperties{
// Crate name can be a predefined value as this is a staticlib and
// it does not need to be unique. The crate name is used for name
// mangling, but it is mixed with the metadata for that purpose, which we
// already set to the module name.
crateName: "generated_rust_staticlib",
is64Bit: toolchain.Is64Bit(),
targetTriple: toolchain.RustTriple(),
bootstrap: ccModule.Bootstrap(),
inRecovery: ccModule.InRecovery(),
inRamdisk: ccModule.InRamdisk(),
inVendorRamdisk: ccModule.InVendorRamdisk(),
// crateType indicates what type of crate to build
crateType: "staticlib",
// synthetic indicates whether this is an actual Rust module or not
synthetic: true,
}
rustFlags = CommonDefaultFlags(ctx, toolchain, rustFlags)
rustFlags = CommonLibraryCompilerFlags(ctx, rustFlags)
rustFlags.GlobalRustFlags = append(rustFlags.GlobalRustFlags, "-C lto=thin")
rustFlags.EmitXrefs = false
return transformSrctoCrate(ctx, mainSrc, rustPathDeps, rustFlags, outputFile, t).outputFile
}
func TransformSrctoDylib(ctx ModuleContext, mainSrc android.Path, deps PathDeps, flags Flags,
outputFile android.WritablePath) buildOutput {
flags.GlobalRustFlags = append(flags.GlobalRustFlags, "-C lto=thin")
return transformSrctoCrate(ctx, mainSrc, deps, flags, outputFile, "dylib")
return transformSrctoCrate(ctx, mainSrc, deps, flags, outputFile, getTransformProperties(ctx, "dylib"))
}
func TransformSrctoStatic(ctx ModuleContext, mainSrc android.Path, deps PathDeps, flags Flags,
outputFile android.WritablePath) buildOutput {
flags.GlobalRustFlags = append(flags.GlobalRustFlags, "-C lto=thin")
return transformSrctoCrate(ctx, mainSrc, deps, flags, outputFile, "staticlib")
return transformSrctoCrate(ctx, mainSrc, deps, flags, outputFile, getTransformProperties(ctx, "staticlib"))
}
func TransformSrctoShared(ctx ModuleContext, mainSrc android.Path, deps PathDeps, flags Flags,
outputFile android.WritablePath) buildOutput {
flags.GlobalRustFlags = append(flags.GlobalRustFlags, "-C lto=thin")
return transformSrctoCrate(ctx, mainSrc, deps, flags, outputFile, "cdylib")
return transformSrctoCrate(ctx, mainSrc, deps, flags, outputFile, getTransformProperties(ctx, "cdylib"))
}
func TransformSrctoProcMacro(ctx ModuleContext, mainSrc android.Path, deps PathDeps,
flags Flags, outputFile android.WritablePath) buildOutput {
return transformSrctoCrate(ctx, mainSrc, deps, flags, outputFile, "proc-macro")
return transformSrctoCrate(ctx, mainSrc, deps, flags, outputFile, getTransformProperties(ctx, "proc-macro"))
}
func rustLibsToPaths(libs RustLibraries) android.Paths {
@ -185,18 +263,18 @@ func makeLibFlags(deps PathDeps) []string {
return libFlags
}
func rustEnvVars(ctx ModuleContext, deps PathDeps) []string {
func rustEnvVars(ctx android.ModuleContext, deps PathDeps, crateName string, cargoOutDir android.OptionalPath) []string {
var envVars []string
// libstd requires a specific environment variable to be set. This is
// not officially documented and may be removed in the future. See
// https://github.com/rust-lang/rust/blob/master/library/std/src/env.rs#L866.
if ctx.RustModule().CrateName() == "std" {
envVars = append(envVars, "STD_ENV_ARCH="+config.StdEnvArch[ctx.RustModule().Arch().ArchType])
if crateName == "std" {
envVars = append(envVars, "STD_ENV_ARCH="+config.StdEnvArch[ctx.Arch().ArchType])
}
if len(deps.SrcDeps) > 0 {
moduleGenDir := ctx.RustModule().compiler.cargoOutDir()
if len(deps.SrcDeps) > 0 && cargoOutDir.Valid() {
moduleGenDir := cargoOutDir
// We must calculate an absolute path for OUT_DIR since Rust's include! macro (which normally consumes this)
// assumes that paths are relative to the source file.
var outDirPrefix string
@ -215,13 +293,15 @@ func rustEnvVars(ctx ModuleContext, deps PathDeps) []string {
envVars = append(envVars, "ANDROID_RUST_VERSION="+config.GetRustVersion(ctx))
if ctx.RustModule().compiler.cargoEnvCompat() {
if bin, ok := ctx.RustModule().compiler.(*binaryDecorator); ok {
if rustMod, ok := ctx.Module().(*Module); ok && rustMod.compiler.cargoEnvCompat() {
// We only emulate cargo environment variables for 3p code, which is only ever built
// by defining a Rust module, so we only need to set these for true Rust modules.
if bin, ok := rustMod.compiler.(*binaryDecorator); ok {
envVars = append(envVars, "CARGO_BIN_NAME="+bin.getStem(ctx))
}
envVars = append(envVars, "CARGO_CRATE_NAME="+ctx.RustModule().CrateName())
envVars = append(envVars, "CARGO_PKG_NAME="+ctx.RustModule().CrateName())
pkgVersion := ctx.RustModule().compiler.cargoPkgVersion()
envVars = append(envVars, "CARGO_CRATE_NAME="+crateName)
envVars = append(envVars, "CARGO_PKG_NAME="+crateName)
pkgVersion := rustMod.compiler.cargoPkgVersion()
if pkgVersion != "" {
envVars = append(envVars, "CARGO_PKG_VERSION="+pkgVersion)
@ -245,8 +325,8 @@ func rustEnvVars(ctx ModuleContext, deps PathDeps) []string {
return envVars
}
func transformSrctoCrate(ctx ModuleContext, main android.Path, deps PathDeps, flags Flags,
outputFile android.WritablePath, crateType string) buildOutput {
func transformSrctoCrate(ctx android.ModuleContext, main android.Path, deps PathDeps, flags Flags,
outputFile android.WritablePath, t transformProperties) buildOutput {
var inputs android.Paths
var implicits android.Paths
@ -256,23 +336,21 @@ func transformSrctoCrate(ctx ModuleContext, main android.Path, deps PathDeps, fl
var earlyLinkFlags string
output.outputFile = outputFile
crateName := ctx.RustModule().CrateName()
targetTriple := ctx.toolchain().RustTriple()
envVars := rustEnvVars(ctx, deps)
envVars := rustEnvVars(ctx, deps, t.crateName, t.cargoOutDir)
inputs = append(inputs, main)
// Collect rustc flags
rustcFlags = append(rustcFlags, flags.GlobalRustFlags...)
rustcFlags = append(rustcFlags, flags.RustFlags...)
rustcFlags = append(rustcFlags, "--crate-type="+crateType)
if crateName != "" {
rustcFlags = append(rustcFlags, "--crate-name="+crateName)
rustcFlags = append(rustcFlags, "--crate-type="+t.crateType)
if t.crateName != "" {
rustcFlags = append(rustcFlags, "--crate-name="+t.crateName)
}
if targetTriple != "" {
rustcFlags = append(rustcFlags, "--target="+targetTriple)
linkFlags = append(linkFlags, "-target "+targetTriple)
if t.targetTriple != "" {
rustcFlags = append(rustcFlags, "--target="+t.targetTriple)
linkFlags = append(linkFlags, "-target "+t.targetTriple)
}
// Suppress an implicit sysroot
@ -302,9 +380,9 @@ func transformSrctoCrate(ctx ModuleContext, main android.Path, deps PathDeps, fl
linkFlags = append(linkFlags, flags.LinkFlags...)
// Check if this module needs to use the bootstrap linker
if ctx.RustModule().Bootstrap() && !ctx.RustModule().InRecovery() && !ctx.RustModule().InRamdisk() && !ctx.RustModule().InVendorRamdisk() {
if t.bootstrap && !t.inRecovery && !t.inRamdisk && !t.inVendorRamdisk {
dynamicLinker := "-Wl,-dynamic-linker,/system/bin/bootstrap/linker"
if ctx.toolchain().Is64Bit() {
if t.is64Bit {
dynamicLinker += "64"
}
linkFlags = append(linkFlags, dynamicLinker)
@ -326,49 +404,56 @@ func transformSrctoCrate(ctx ModuleContext, main android.Path, deps PathDeps, fl
orderOnly = append(orderOnly, deps.SharedLibs...)
if len(deps.SrcDeps) > 0 {
moduleGenDir := ctx.RustModule().compiler.cargoOutDir()
var outputs android.WritablePaths
if !t.synthetic {
// Only worry about OUT_DIR for actual Rust modules.
// Libraries built from cc use generated source, and do not utilize OUT_DIR.
if len(deps.SrcDeps) > 0 {
var outputs android.WritablePaths
for _, genSrc := range deps.SrcDeps {
if android.SuffixInList(outputs.Strings(), genSubDir+genSrc.Base()) {
ctx.PropertyErrorf("srcs",
"multiple source providers generate the same filename output: "+genSrc.Base())
for _, genSrc := range deps.SrcDeps {
if android.SuffixInList(outputs.Strings(), genSubDir+genSrc.Base()) {
ctx.PropertyErrorf("srcs",
"multiple source providers generate the same filename output: "+genSrc.Base())
}
outputs = append(outputs, android.PathForModuleOut(ctx, genSubDir+genSrc.Base()))
}
outputs = append(outputs, android.PathForModuleOut(ctx, genSubDir+genSrc.Base()))
}
ctx.Build(pctx, android.BuildParams{
Rule: cp,
Description: "cp " + moduleGenDir.Path().Rel(),
Outputs: outputs,
Inputs: deps.SrcDeps,
Args: map[string]string{
"outDir": moduleGenDir.String(),
},
})
implicits = append(implicits, outputs.Paths()...)
ctx.Build(pctx, android.BuildParams{
Rule: cp,
Description: "cp " + t.cargoOutDir.Path().Rel(),
Outputs: outputs,
Inputs: deps.SrcDeps,
Args: map[string]string{
"outDir": t.cargoOutDir.String(),
},
})
implicits = append(implicits, outputs.Paths()...)
}
}
if flags.Clippy {
clippyFile := android.PathForModuleOut(ctx, outputFile.Base()+".clippy")
ctx.Build(pctx, android.BuildParams{
Rule: clippyDriver,
Description: "clippy " + main.Rel(),
Output: clippyFile,
ImplicitOutputs: nil,
Inputs: inputs,
Implicits: implicits,
OrderOnly: orderOnly,
Args: map[string]string{
"rustcFlags": strings.Join(rustcFlags, " "),
"libFlags": strings.Join(libFlags, " "),
"clippyFlags": strings.Join(flags.ClippyFlags, " "),
"envVars": strings.Join(envVars, " "),
},
})
// Declare the clippy build as an implicit dependency of the original crate.
implicits = append(implicits, clippyFile)
if !t.synthetic {
// Only worry about clippy for actual Rust modules.
// Libraries built from cc use generated source, and don't need to run clippy.
if flags.Clippy {
clippyFile := android.PathForModuleOut(ctx, outputFile.Base()+".clippy")
ctx.Build(pctx, android.BuildParams{
Rule: clippyDriver,
Description: "clippy " + main.Rel(),
Output: clippyFile,
ImplicitOutputs: nil,
Inputs: inputs,
Implicits: implicits,
OrderOnly: orderOnly,
Args: map[string]string{
"rustcFlags": strings.Join(rustcFlags, " "),
"libFlags": strings.Join(libFlags, " "),
"clippyFlags": strings.Join(flags.ClippyFlags, " "),
"envVars": strings.Join(envVars, " "),
},
})
// Declare the clippy build as an implicit dependency of the original crate.
implicits = append(implicits, clippyFile)
}
}
ctx.Build(pctx, android.BuildParams{
@ -389,25 +474,28 @@ func transformSrctoCrate(ctx ModuleContext, main android.Path, deps PathDeps, fl
},
})
if flags.EmitXrefs {
kytheFile := android.PathForModuleOut(ctx, outputFile.Base()+".kzip")
ctx.Build(pctx, android.BuildParams{
Rule: kytheExtract,
Description: "Xref Rust extractor " + main.Rel(),
Output: kytheFile,
Inputs: inputs,
Implicits: implicits,
OrderOnly: orderOnly,
Args: map[string]string{
"rustcFlags": strings.Join(rustcFlags, " "),
"linkFlags": strings.Join(linkFlags, " "),
"libFlags": strings.Join(libFlags, " "),
"crtBegin": strings.Join(deps.CrtBegin.Strings(), " "),
"crtEnd": strings.Join(deps.CrtEnd.Strings(), " "),
"envVars": strings.Join(envVars, " "),
},
})
output.kytheFile = kytheFile
if !t.synthetic {
// Only emit xrefs for true Rust modules.
if flags.EmitXrefs {
kytheFile := android.PathForModuleOut(ctx, outputFile.Base()+".kzip")
ctx.Build(pctx, android.BuildParams{
Rule: kytheExtract,
Description: "Xref Rust extractor " + main.Rel(),
Output: kytheFile,
Inputs: inputs,
Implicits: implicits,
OrderOnly: orderOnly,
Args: map[string]string{
"rustcFlags": strings.Join(rustcFlags, " "),
"linkFlags": strings.Join(linkFlags, " "),
"libFlags": strings.Join(libFlags, " "),
"crtBegin": strings.Join(deps.CrtBegin.Strings(), " "),
"crtEnd": strings.Join(deps.CrtEnd.Strings(), " "),
"envVars": strings.Join(envVars, " "),
},
})
output.kytheFile = kytheFile
}
}
return output
}
@ -457,7 +545,7 @@ func Rustdoc(ctx ModuleContext, main android.Path, deps PathDeps,
Args: map[string]string{
"rustdocFlags": strings.Join(rustdocFlags, " "),
"outDir": docDir.String(),
"envVars": strings.Join(rustEnvVars(ctx, deps), " "),
"envVars": strings.Join(rustEnvVars(ctx, deps, crateName, ctx.RustModule().compiler.cargoOutDir()), " "),
},
})

View file

@ -46,6 +46,9 @@ func TestSourceProviderCollision(t *testing.T) {
}
func TestCompilationOutputFiles(t *testing.T) {
// Note: Rustdoc output is produced for the PrimaryModule, so if the variant
// order changes, then it may be produced for a different variant.
ctx := testRust(t, `
rust_library {
name: "libfizz_buzz",
@ -125,6 +128,16 @@ func TestCompilationOutputFiles(t *testing.T) {
"out/soong/.intermediates/librust_ffi/android_arm64_armv8-a_static/rustdoc.timestamp",
},
},
{
testName: "rust_ffi rlib",
moduleName: "librust_ffi",
variant: "android_arm64_armv8-a_rlib_rlib-std",
expectedFiles: []string{
"out/soong/.intermediates/librust_ffi/android_arm64_armv8-a_rlib_rlib-std/librust_ffi.rlib",
"out/soong/.intermediates/librust_ffi/android_arm64_armv8-a_rlib_rlib-std/librust_ffi.rlib.clippy",
"out/soong/.intermediates/librust_ffi/android_arm64_armv8-a_rlib_rlib-std/meta_lic",
},
},
{
testName: "rust_ffi shared",
moduleName: "librust_ffi",

View file

@ -322,9 +322,9 @@ func (compiler *baseCompiler) compilerProps() []interface{} {
return []interface{}{&compiler.Properties}
}
func (compiler *baseCompiler) cfgsToFlags() []string {
func cfgsToFlags(cfgs []string) []string {
flags := []string{}
for _, cfg := range compiler.Properties.Cfgs {
for _, cfg := range cfgs {
flags = append(flags, "--cfg '"+cfg+"'")
}
@ -351,23 +351,61 @@ func (compiler *baseCompiler) featureFlags(ctx ModuleContext, flags Flags) Flags
return flags
}
func (compiler *baseCompiler) cfgFlags(ctx ModuleContext, flags Flags) Flags {
if ctx.RustModule().InVendorOrProduct() {
compiler.Properties.Cfgs = append(compiler.Properties.Cfgs, "android_vndk")
if ctx.RustModule().InVendor() {
compiler.Properties.Cfgs = append(compiler.Properties.Cfgs, "android_vendor")
} else if ctx.RustModule().InProduct() {
compiler.Properties.Cfgs = append(compiler.Properties.Cfgs, "android_product")
func CommonDefaultCfgFlags(flags Flags, vendor bool, product bool) Flags {
var cfgs []string
if vendor || product {
cfgs = append(cfgs, "android_vndk")
if vendor {
cfgs = append(cfgs, "android_vendor")
} else if product {
cfgs = append(cfgs, "android_product")
}
}
flags.RustFlags = append(flags.RustFlags, compiler.cfgsToFlags()...)
flags.RustdocFlags = append(flags.RustdocFlags, compiler.cfgsToFlags()...)
flags.RustFlags = append(flags.RustFlags, cfgsToFlags(cfgs)...)
flags.RustdocFlags = append(flags.RustdocFlags, cfgsToFlags(cfgs)...)
return flags
}
func (compiler *baseCompiler) cfgFlags(ctx ModuleContext, flags Flags) Flags {
flags = CommonDefaultCfgFlags(flags, ctx.RustModule().InVendor(), ctx.RustModule().InProduct())
flags.RustFlags = append(flags.RustFlags, cfgsToFlags(compiler.Properties.Cfgs)...)
flags.RustdocFlags = append(flags.RustdocFlags, cfgsToFlags(compiler.Properties.Cfgs)...)
return flags
}
func CommonDefaultFlags(ctx android.ModuleContext, toolchain config.Toolchain, flags Flags) Flags {
flags.GlobalRustFlags = append(flags.GlobalRustFlags, config.GlobalRustFlags...)
flags.GlobalRustFlags = append(flags.GlobalRustFlags, toolchain.ToolchainRustFlags())
flags.GlobalLinkFlags = append(flags.GlobalLinkFlags, toolchain.ToolchainLinkFlags())
flags.EmitXrefs = ctx.Config().EmitXrefRules()
if ctx.Host() && !ctx.Windows() {
flags.LinkFlags = append(flags.LinkFlags, cc.RpathFlags(ctx)...)
}
if ctx.Os() == android.Linux {
// Add -lc, -lrt, -ldl, -lpthread, -lm and -lgcc_s to glibc builds to match
// the default behavior of device builds.
flags.LinkFlags = append(flags.LinkFlags, config.LinuxHostGlobalLinkFlags...)
} else if ctx.Os() == android.Darwin {
// Add -lc, -ldl, -lpthread and -lm to glibc darwin builds to match the default
// behavior of device builds.
flags.LinkFlags = append(flags.LinkFlags,
"-lc",
"-ldl",
"-lpthread",
"-lm",
)
}
return flags
}
func (compiler *baseCompiler) compilerFlags(ctx ModuleContext, flags Flags) Flags {
flags = CommonDefaultFlags(ctx, ctx.toolchain(), flags)
lintFlags, err := config.RustcLintsForDir(ctx.ModuleDir(), compiler.Properties.Lints)
if err != nil {
ctx.PropertyErrorf("lints", err.Error())
@ -396,29 +434,7 @@ func (compiler *baseCompiler) compilerFlags(ctx ModuleContext, flags Flags) Flag
flags.RustFlags = append(flags.RustFlags, "--edition="+compiler.edition())
flags.RustdocFlags = append(flags.RustdocFlags, "--edition="+compiler.edition())
flags.LinkFlags = append(flags.LinkFlags, compiler.Properties.Ld_flags...)
flags.GlobalRustFlags = append(flags.GlobalRustFlags, config.GlobalRustFlags...)
flags.GlobalRustFlags = append(flags.GlobalRustFlags, ctx.toolchain().ToolchainRustFlags())
flags.GlobalLinkFlags = append(flags.GlobalLinkFlags, ctx.toolchain().ToolchainLinkFlags())
flags.EmitXrefs = ctx.Config().EmitXrefRules()
if ctx.Host() && !ctx.Windows() {
flags.LinkFlags = append(flags.LinkFlags, cc.RpathFlags(ctx)...)
}
if ctx.Os() == android.Linux {
// Add -lc, -lrt, -ldl, -lpthread, -lm and -lgcc_s to glibc builds to match
// the default behavior of device builds.
flags.LinkFlags = append(flags.LinkFlags, config.LinuxHostGlobalLinkFlags...)
} else if ctx.Os() == android.Darwin {
// Add -lc, -ldl, -lpthread and -lm to glibc darwin builds to match the default
// behavior of device builds.
flags.LinkFlags = append(flags.LinkFlags,
"-lc",
"-ldl",
"-lpthread",
"-lm",
)
}
return flags
}
@ -568,11 +584,11 @@ func (compiler *baseCompiler) installTestData(ctx ModuleContext, data []android.
compiler.installDeps = append(compiler.installDeps, installedData...)
}
func (compiler *baseCompiler) getStem(ctx ModuleContext) string {
func (compiler *baseCompiler) getStem(ctx android.ModuleContext) string {
return compiler.getStemWithoutSuffix(ctx) + String(compiler.Properties.Suffix)
}
func (compiler *baseCompiler) getStemWithoutSuffix(ctx BaseModuleContext) string {
func (compiler *baseCompiler) getStemWithoutSuffix(ctx android.BaseModuleContext) string {
stem := ctx.ModuleName()
if String(compiler.Properties.Stem) != "" {
stem = String(compiler.Properties.Stem)

View file

@ -47,7 +47,7 @@ func (cov *coverage) deps(ctx DepsContext, deps Deps) Deps {
// no_std modules are missing libprofiler_builtins which provides coverage, so we need to add it as a dependency.
if rustModule, ok := ctx.Module().(*Module); ok && rustModule.compiler.noStdlibs() {
ctx.AddVariationDependencies([]blueprint.Variation{{Mutator: "rust_libraries", Variation: "rlib"}}, rlibDepTag, ProfilerBuiltins)
ctx.AddVariationDependencies([]blueprint.Variation{{Mutator: "rust_libraries", Variation: "rlib"}, {Mutator: "link", Variation: ""}}, rlibDepTag, ProfilerBuiltins)
}
}

View file

@ -120,13 +120,17 @@ func TestCCFuzzDepBundling(t *testing.T) {
}
cc_fuzz {
name: "fuzz_static_libtest",
static_rlibs: ["libtest_fuzzing"],
}
cc_fuzz {
name: "fuzz_staticffi_libtest",
static_libs: ["libtest_fuzzing"],
}
`)
fuzz_shared_libtest := ctx.ModuleForTests("fuzz_shared_libtest", "android_arm64_armv8-a_fuzzer").Module().(cc.LinkableInterface)
fuzz_static_libtest := ctx.ModuleForTests("fuzz_static_libtest", "android_arm64_armv8-a_fuzzer").Module().(cc.LinkableInterface)
fuzz_staticffi_libtest := ctx.ModuleForTests("fuzz_staticffi_libtest", "android_arm64_armv8-a_fuzzer").Module().(cc.LinkableInterface)
if !strings.Contains(fuzz_shared_libtest.FuzzSharedLibraries().String(), ":libcc_transitive_dep.so") {
t.Errorf("cc_fuzz does not contain the expected bundled transitive shared libs from rust_ffi_shared ('libcc_transitive_dep'): %#v", fuzz_shared_libtest.FuzzSharedLibraries().String())
@ -134,4 +138,7 @@ func TestCCFuzzDepBundling(t *testing.T) {
if !strings.Contains(fuzz_static_libtest.FuzzSharedLibraries().String(), ":libcc_transitive_dep.so") {
t.Errorf("cc_fuzz does not contain the expected bundled transitive shared libs from rust_ffi_static ('libcc_transitive_dep'): %#v", fuzz_static_libtest.FuzzSharedLibraries().String())
}
if !strings.Contains(fuzz_staticffi_libtest.FuzzSharedLibraries().String(), ":libcc_transitive_dep.so") {
t.Errorf("cc_fuzz does not contain the expected bundled transitive shared libs from rust_ffi_rlib ('libcc_transitive_dep'): %#v", fuzz_staticffi_libtest.FuzzSharedLibraries().String())
}
}

View file

@ -22,33 +22,45 @@ import (
"android/soong/cc"
)
// Test that cc modules can link against vendor_available rust_ffi_static libraries.
// Test that cc modules can link against vendor_available rust_ffi_rlib/rust_ffi_static libraries.
func TestVendorLinkage(t *testing.T) {
ctx := testRust(t, `
cc_binary {
name: "fizz_vendor",
static_libs: ["libfoo_vendor"],
name: "fizz_vendor_available",
static_libs: ["libfoo_vendor_static"],
static_rlibs: ["libfoo_vendor"],
vendor_available: true,
}
cc_binary {
name: "fizz_soc_specific",
static_rlibs: ["libfoo_vendor"],
soc_specific: true,
}
rust_ffi_static {
rust_ffi_rlib {
name: "libfoo_vendor",
crate_name: "foo",
srcs: ["foo.rs"],
vendor_available: true,
}
rust_ffi_static {
name: "libfoo_vendor_static",
crate_name: "foo",
srcs: ["foo.rs"],
vendor_available: true,
}
`)
vendorBinary := ctx.ModuleForTests("fizz_vendor", "android_vendor_arm64_armv8-a").Module().(*cc.Module)
vendorBinary := ctx.ModuleForTests("fizz_vendor_available", "android_vendor_arm64_armv8-a").Module().(*cc.Module)
if !android.InList("libfoo_vendor.vendor", vendorBinary.Properties.AndroidMkStaticLibs) {
t.Errorf("vendorBinary should have a dependency on libfoo_vendor: %#v", vendorBinary.Properties.AndroidMkStaticLibs)
if !android.InList("libfoo_vendor_static.vendor", vendorBinary.Properties.AndroidMkStaticLibs) {
t.Errorf("vendorBinary should have a dependency on libfoo_vendor_static.vendor: %#v", vendorBinary.Properties.AndroidMkStaticLibs)
}
}
// Test that variants which use the vndk emit the appropriate cfg flag.
func TestImageCfgFlag(t *testing.T) {
ctx := testRust(t, `
rust_ffi_static {
rust_ffi_shared {
name: "libfoo",
crate_name: "foo",
srcs: ["foo.rs"],
@ -57,7 +69,7 @@ func TestImageCfgFlag(t *testing.T) {
}
`)
vendor := ctx.ModuleForTests("libfoo", "android_vendor_arm64_armv8-a_static").Rule("rustc")
vendor := ctx.ModuleForTests("libfoo", "android_vendor_arm64_armv8-a_shared").Rule("rustc")
if !strings.Contains(vendor.Args["rustcFlags"], "--cfg 'android_vndk'") {
t.Errorf("missing \"--cfg 'android_vndk'\" for libfoo vendor variant, rustcFlags: %#v", vendor.Args["rustcFlags"])
@ -69,7 +81,7 @@ func TestImageCfgFlag(t *testing.T) {
t.Errorf("unexpected \"--cfg 'android_product'\" for libfoo vendor variant, rustcFlags: %#v", vendor.Args["rustcFlags"])
}
product := ctx.ModuleForTests("libfoo", "android_product_arm64_armv8-a_static").Rule("rustc")
product := ctx.ModuleForTests("libfoo", "android_product_arm64_armv8-a_shared").Rule("rustc")
if !strings.Contains(product.Args["rustcFlags"], "--cfg 'android_vndk'") {
t.Errorf("missing \"--cfg 'android_vndk'\" for libfoo product variant, rustcFlags: %#v", product.Args["rustcFlags"])
}
@ -80,7 +92,7 @@ func TestImageCfgFlag(t *testing.T) {
t.Errorf("missing \"--cfg 'android_product'\" for libfoo product variant, rustcFlags: %#v", product.Args["rustcFlags"])
}
system := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_static").Rule("rustc")
system := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_shared").Rule("rustc")
if strings.Contains(system.Args["rustcFlags"], "--cfg 'android_vndk'") {
t.Errorf("unexpected \"--cfg 'android_vndk'\" for libfoo system variant, rustcFlags: %#v", system.Args["rustcFlags"])
}
@ -93,27 +105,34 @@ func TestImageCfgFlag(t *testing.T) {
}
// Test that cc modules can link against vendor_ramdisk_available rust_ffi_static libraries.
// Test that cc modules can link against vendor_ramdisk_available rust_ffi_rlib and rust_ffi_static libraries.
func TestVendorRamdiskLinkage(t *testing.T) {
ctx := testRust(t, `
cc_library_static {
cc_library_shared {
name: "libcc_vendor_ramdisk",
static_libs: ["libfoo_vendor_ramdisk"],
static_rlibs: ["libfoo_vendor_ramdisk"],
static_libs: ["libfoo_static_vendor_ramdisk"],
system_shared_libs: [],
vendor_ramdisk_available: true,
}
rust_ffi_static {
rust_ffi_rlib {
name: "libfoo_vendor_ramdisk",
crate_name: "foo",
srcs: ["foo.rs"],
vendor_ramdisk_available: true,
}
rust_ffi_static {
name: "libfoo_static_vendor_ramdisk",
crate_name: "foo",
srcs: ["foo.rs"],
vendor_ramdisk_available: true,
}
`)
vendorRamdiskLibrary := ctx.ModuleForTests("libcc_vendor_ramdisk", "android_vendor_ramdisk_arm64_armv8-a_static").Module().(*cc.Module)
vendorRamdiskLibrary := ctx.ModuleForTests("libcc_vendor_ramdisk", "android_vendor_ramdisk_arm64_armv8-a_shared").Module().(*cc.Module)
if !android.InList("libfoo_vendor_ramdisk.vendor_ramdisk", vendorRamdiskLibrary.Properties.AndroidMkStaticLibs) {
t.Errorf("libcc_vendor_ramdisk should have a dependency on libfoo_vendor_ramdisk")
if !android.InList("libfoo_static_vendor_ramdisk.vendor_ramdisk", vendorRamdiskLibrary.Properties.AndroidMkStaticLibs) {
t.Errorf("libcc_vendor_ramdisk should have a dependency on libfoo_static_vendor_ramdisk")
}
}

View file

@ -37,10 +37,15 @@ func init() {
android.RegisterModuleType("rust_library_host_rlib", RustLibraryRlibHostFactory)
android.RegisterModuleType("rust_ffi", RustFFIFactory)
android.RegisterModuleType("rust_ffi_shared", RustFFISharedFactory)
android.RegisterModuleType("rust_ffi_static", RustFFIStaticFactory)
android.RegisterModuleType("rust_ffi_rlib", RustFFIRlibFactory)
android.RegisterModuleType("rust_ffi_host", RustFFIHostFactory)
android.RegisterModuleType("rust_ffi_host_shared", RustFFISharedHostFactory)
android.RegisterModuleType("rust_ffi_host_static", RustFFIStaticHostFactory)
android.RegisterModuleType("rust_ffi_host_rlib", RustFFIRlibHostFactory)
// TODO: Remove when all instances of rust_ffi_static have been switched to rust_ffi_rlib
// Alias rust_ffi_static to the combined rust_ffi_rlib factory
android.RegisterModuleType("rust_ffi_static", RustFFIStaticRlibFactory)
android.RegisterModuleType("rust_ffi_host_static", RustFFIStaticRlibHostFactory)
}
type VariantLibraryProperties struct {
@ -104,6 +109,8 @@ type libraryDecorator struct {
includeDirs android.Paths
sourceProvider SourceProvider
isFFI bool
// table-of-contents file for cdylib crates to optimize out relinking when possible
tocFile android.OptionalPath
}
@ -143,6 +150,8 @@ type libraryInterface interface {
BuildOnlyShared()
toc() android.OptionalPath
isFFILibrary() bool
}
func (library *libraryDecorator) nativeCoverage() bool {
@ -250,7 +259,7 @@ func (library *libraryDecorator) autoDep(ctx android.BottomUpMutatorContext) aut
}
func (library *libraryDecorator) stdLinkage(ctx *depsContext) RustLinkage {
if library.static() || library.MutatedProperties.VariantIsStaticStd {
if library.static() || library.MutatedProperties.VariantIsStaticStd || (library.rlib() && library.isFFILibrary()) {
return RlibLinkage
} else if library.baseCompiler.preferRlib() {
return RlibLinkage
@ -270,8 +279,8 @@ func RustLibraryFactory() android.Module {
return module.Init()
}
// rust_ffi produces all FFI variants (rust_ffi_shared and
// rust_ffi_static).
// rust_ffi produces all FFI variants (rust_ffi_shared, rust_ffi_static, and
// rust_ffi_rlib).
func RustFFIFactory() android.Module {
module, library := NewRustLibrary(android.HostAndDeviceSupported)
library.BuildOnlyFFI()
@ -300,14 +309,6 @@ func RustFFISharedFactory() android.Module {
return module.Init()
}
// rust_ffi_static produces a static library (Rust crate type
// "staticlib").
func RustFFIStaticFactory() android.Module {
module, library := NewRustLibrary(android.HostAndDeviceSupported)
library.BuildOnlyStatic()
return module.Init()
}
// rust_library_host produces all Rust variants for the host
// (rust_library_dylib_host and rust_library_rlib_host).
func RustLibraryHostFactory() android.Module {
@ -317,7 +318,7 @@ func RustLibraryHostFactory() android.Module {
}
// rust_ffi_host produces all FFI variants for the host
// (rust_ffi_static_host and rust_ffi_shared_host).
// (rust_ffi_rlib_host, rust_ffi_static_host, and rust_ffi_shared_host).
func RustFFIHostFactory() android.Module {
module, library := NewRustLibrary(android.HostSupported)
library.BuildOnlyFFI()
@ -340,14 +341,6 @@ func RustLibraryRlibHostFactory() android.Module {
return module.Init()
}
// rust_ffi_static_host produces a static library for the host (Rust
// crate type "staticlib").
func RustFFIStaticHostFactory() android.Module {
module, library := NewRustLibrary(android.HostSupported)
library.BuildOnlyStatic()
return module.Init()
}
// rust_ffi_shared_host produces an shared library for the host (Rust
// crate type "cdylib").
func RustFFISharedHostFactory() android.Module {
@ -356,11 +349,51 @@ func RustFFISharedHostFactory() android.Module {
return module.Init()
}
// rust_ffi_rlib_host produces an rlib for the host (Rust crate
// type "rlib").
func RustFFIRlibHostFactory() android.Module {
module, library := NewRustLibrary(android.HostSupported)
library.BuildOnlyRlibStatic()
library.isFFI = true
return module.Init()
}
// rust_ffi_rlib produces an rlib (Rust crate type "rlib").
func RustFFIRlibFactory() android.Module {
module, library := NewRustLibrary(android.HostAndDeviceSupported)
library.BuildOnlyRlib()
library.isFFI = true
return module.Init()
}
// rust_ffi_static produces a staticlib and an rlib variant
func RustFFIStaticRlibFactory() android.Module {
module, library := NewRustLibrary(android.HostAndDeviceSupported)
library.BuildOnlyRlibStatic()
library.isFFI = true
return module.Init()
}
// rust_ffi_static_host produces a staticlib and an rlib variant for the host
func RustFFIStaticRlibHostFactory() android.Module {
module, library := NewRustLibrary(android.HostSupported)
library.BuildOnlyRlibStatic()
library.isFFI = true
return module.Init()
}
func (library *libraryDecorator) BuildOnlyFFI() {
library.MutatedProperties.BuildDylib = false
library.MutatedProperties.BuildRlib = false
// we build rlibs for later static ffi linkage.
library.MutatedProperties.BuildRlib = true
library.MutatedProperties.BuildShared = true
library.MutatedProperties.BuildStatic = true
library.isFFI = true
}
func (library *libraryDecorator) BuildOnlyRust() {
@ -384,11 +417,21 @@ func (library *libraryDecorator) BuildOnlyRlib() {
library.MutatedProperties.BuildStatic = false
}
func (library *libraryDecorator) BuildOnlyRlibStatic() {
library.MutatedProperties.BuildDylib = false
library.MutatedProperties.BuildRlib = true
library.MutatedProperties.BuildShared = false
library.MutatedProperties.BuildStatic = true
library.isFFI = true
}
func (library *libraryDecorator) BuildOnlyStatic() {
library.MutatedProperties.BuildRlib = false
library.MutatedProperties.BuildDylib = false
library.MutatedProperties.BuildShared = false
library.MutatedProperties.BuildStatic = true
library.isFFI = true
}
func (library *libraryDecorator) BuildOnlyShared() {
@ -396,6 +439,12 @@ func (library *libraryDecorator) BuildOnlyShared() {
library.MutatedProperties.BuildDylib = false
library.MutatedProperties.BuildStatic = false
library.MutatedProperties.BuildShared = true
library.isFFI = true
}
func (library *libraryDecorator) isFFILibrary() bool {
return library.isFFI
}
func NewRustLibrary(hod android.HostOrDeviceSupported) (*Module, *libraryDecorator) {
@ -446,8 +495,15 @@ func (library *libraryDecorator) sharedLibFilename(ctx ModuleContext) string {
return library.getStem(ctx) + ctx.toolchain().SharedLibSuffix()
}
// Library cfg flags common to all variants
func CommonLibraryCfgFlags(ctx android.ModuleContext, flags Flags) Flags {
return flags
}
func (library *libraryDecorator) cfgFlags(ctx ModuleContext, flags Flags) Flags {
flags = library.baseCompiler.cfgFlags(ctx, flags)
flags = CommonLibraryCfgFlags(ctx, flags)
if library.dylib() {
// We need to add a dependency on std in order to link crates as dylibs.
// The hack to add this dependency is guarded by the following cfg so
@ -455,8 +511,15 @@ func (library *libraryDecorator) cfgFlags(ctx ModuleContext, flags Flags) Flags
library.baseCompiler.Properties.Cfgs = append(library.baseCompiler.Properties.Cfgs, "android_dylib")
}
flags.RustFlags = append(flags.RustFlags, library.baseCompiler.cfgsToFlags()...)
flags.RustdocFlags = append(flags.RustdocFlags, library.baseCompiler.cfgsToFlags()...)
flags.RustFlags = append(flags.RustFlags, cfgsToFlags(library.baseCompiler.Properties.Cfgs)...)
flags.RustdocFlags = append(flags.RustdocFlags, cfgsToFlags(library.baseCompiler.Properties.Cfgs)...)
return flags
}
// Common flags applied to all libraries irrespective of properties or variant should be included here
func CommonLibraryCompilerFlags(ctx android.ModuleContext, flags Flags) Flags {
flags.RustFlags = append(flags.RustFlags, "-C metadata="+ctx.ModuleName())
return flags
}
@ -464,11 +527,13 @@ func (library *libraryDecorator) cfgFlags(ctx ModuleContext, flags Flags) Flags
func (library *libraryDecorator) compilerFlags(ctx ModuleContext, flags Flags) Flags {
flags = library.baseCompiler.compilerFlags(ctx, flags)
flags.RustFlags = append(flags.RustFlags, "-C metadata="+ctx.ModuleName())
if library.shared() || library.static() {
flags = CommonLibraryCompilerFlags(ctx, flags)
if library.isFFI {
library.includeDirs = append(library.includeDirs, android.PathsForModuleSrc(ctx, library.Properties.Include_dirs)...)
library.includeDirs = append(library.includeDirs, android.PathsForModuleSrc(ctx, library.Properties.Export_include_dirs)...)
}
if library.shared() {
if ctx.Darwin() {
flags.LinkFlags = append(
@ -494,6 +559,9 @@ func (library *libraryDecorator) compile(ctx ModuleContext, flags Flags, deps Pa
deps.srcProviderFiles = append(deps.srcProviderFiles, library.sourceProvider.Srcs()...)
}
// Ensure link dirs are not duplicated
deps.linkDirs = android.FirstUniqueStrings(deps.linkDirs)
// Calculate output filename
if library.rlib() {
fileName = library.getStem(ctx) + ctx.toolchain().RlibSuffix()
@ -549,9 +617,10 @@ func (library *libraryDecorator) compile(ctx ModuleContext, flags Flags, deps Pa
library.flagExporter.exportLinkObjects(deps.linkObjects...)
}
if library.static() || library.shared() {
// Since we have FFI rlibs, we need to collect their includes as well
if library.static() || library.shared() || library.rlib() {
android.SetProvider(ctx, cc.FlagExporterInfoProvider, cc.FlagExporterInfo{
IncludeDirs: library.includeDirs,
IncludeDirs: android.FirstUniquePaths(library.includeDirs),
})
}
@ -666,6 +735,11 @@ func LibraryMutator(mctx android.BottomUpMutatorContext) {
return
}
// Don't produce rlib/dylib/source variants for shared or static variants
if library.shared() || library.static() {
return
}
var variants []string
// The source variant is used for SourceProvider modules. The other variants (i.e. rlib and dylib)
// depend on this variant. It must be the first variant to be declared.
@ -705,6 +779,9 @@ func LibraryMutator(mctx android.BottomUpMutatorContext) {
// The source variant does not produce any library.
// Disable the compilation steps.
v.(*Module).compiler.SetDisabled()
case "":
// if there's an empty variant, alias it so it is the default variant
mctx.AliasVariation("")
}
}
@ -729,20 +806,29 @@ func LibstdMutator(mctx android.BottomUpMutatorContext) {
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...)
// If this is a rust_ffi variant it only needs rlib-std
if library.isFFILibrary() {
variants := []string{"rlib-std"}
modules := mctx.CreateLocalVariations(variants...)
rlib := modules[0].(*Module)
rlib.compiler.(libraryInterface).setRlibStd()
rlib.Properties.RustSubName += RlibStdlibSuffix
} else {
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()
if dylib.ModuleBase.ImageVariation().Variation == android.VendorRamdiskVariation {
// TODO(b/165791368)
// Disable rlibs that link against dylib-std on vendor ramdisk variations until those dylib
// variants are properly supported.
dylib.Disable()
rlib := modules[0].(*Module)
dylib := modules[1].(*Module)
rlib.compiler.(libraryInterface).setRlibStd()
dylib.compiler.(libraryInterface).setDylibStd()
if dylib.ModuleBase.ImageVariation().Variation == android.VendorRamdiskVariation {
// TODO(b/165791368)
// Disable rlibs that link against dylib-std on vendor ramdisk variations until those dylib
// variants are properly supported.
dylib.Disable()
}
rlib.Properties.RustSubName += RlibStdlibSuffix
}
rlib.Properties.RustSubName += RlibStdlibSuffix
}
}
}

View file

@ -37,9 +37,10 @@ func TestLibraryVariants(t *testing.T) {
}`)
// Test all variants are being built.
libfooStatic := ctx.ModuleForTests("libfoo.ffi", "linux_glibc_x86_64_static").Rule("rustc")
libfooRlib := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_rlib_rlib-std").Rule("rustc")
libfooDylib := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_dylib").Rule("rustc")
libfooStatic := ctx.ModuleForTests("libfoo.ffi", "linux_glibc_x86_64_static").Rule("rustc")
libfooFFIRlib := ctx.ModuleForTests("libfoo.ffi", "linux_glibc_x86_64_rlib_rlib-std").Rule("rustc")
libfooShared := ctx.ModuleForTests("libfoo.ffi", "linux_glibc_x86_64_shared").Rule("rustc")
rlibCrateType := "rlib"
@ -62,6 +63,11 @@ func TestLibraryVariants(t *testing.T) {
t.Errorf("missing crate-type for static variant, expecting %#v, rustcFlags: %#v", staticCrateType, libfooStatic.Args["rustcFlags"])
}
// Test crate type for FFI rlibs is correct
if !strings.Contains(libfooFFIRlib.Args["rustcFlags"], "crate-type="+rlibCrateType) {
t.Errorf("missing crate-type for static variant, expecting %#v, rustcFlags: %#v", rlibCrateType, libfooFFIRlib.Args["rustcFlags"])
}
// Test crate type for C shared libraries is correct.
if !strings.Contains(libfooShared.Args["rustcFlags"], "crate-type="+sharedCrateType) {
t.Errorf("missing crate-type for shared variant, expecting %#v, got rustcFlags: %#v", sharedCrateType, libfooShared.Args["rustcFlags"])
@ -182,15 +188,20 @@ func TestSharedLibraryToc(t *testing.T) {
func TestStaticLibraryLinkage(t *testing.T) {
ctx := testRust(t, `
rust_ffi_static {
rust_ffi {
name: "libfoo",
srcs: ["foo.rs"],
crate_name: "foo",
}`)
libfoo := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_static")
libfoo := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_rlib_rlib-std")
libfooStatic := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_static")
if !android.InList("libstd", libfoo.Module().(*Module).Properties.AndroidMkRlibs) {
t.Errorf("Static libstd rlib expected to be a dependency of Rust rlib libraries. Rlib deps are: %#v",
libfoo.Module().(*Module).Properties.AndroidMkDylibs)
}
if !android.InList("libstd", libfooStatic.Module().(*Module).Properties.AndroidMkRlibs) {
t.Errorf("Static libstd rlib expected to be a dependency of Rust static libraries. Rlib deps are: %#v",
libfoo.Module().(*Module).Properties.AndroidMkDylibs)
}
@ -198,6 +209,12 @@ func TestStaticLibraryLinkage(t *testing.T) {
func TestNativeDependencyOfRlib(t *testing.T) {
ctx := testRust(t, `
rust_ffi_rlib {
name: "libffi_rlib",
crate_name: "ffi_rlib",
rlibs: ["librust_rlib"],
srcs: ["foo.rs"],
}
rust_ffi_static {
name: "libffi_static",
crate_name: "ffi_static",
@ -224,10 +241,12 @@ func TestNativeDependencyOfRlib(t *testing.T) {
rustRlibRlibStd := ctx.ModuleForTests("librust_rlib", "android_arm64_armv8-a_rlib_rlib-std")
rustRlibDylibStd := ctx.ModuleForTests("librust_rlib", "android_arm64_armv8-a_rlib_dylib-std")
ffiStatic := ctx.ModuleForTests("libffi_static", "android_arm64_armv8-a_static")
ffiRlib := ctx.ModuleForTests("libffi_rlib", "android_arm64_armv8-a_rlib_rlib-std")
modules := []android.TestingModule{
rustRlibRlibStd,
rustRlibDylibStd,
ffiRlib,
ffiStatic,
}
@ -290,27 +309,28 @@ func TestAutoDeps(t *testing.T) {
libfooRlib := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_rlib_rlib-std")
libfooDylib := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_dylib")
libfooFFIRlib := ctx.ModuleForTests("libfoo.ffi", "linux_glibc_x86_64_rlib_rlib-std")
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} {
for _, static := range []android.TestingModule{libfooRlib, libfooStatic, libfooFFIRlib} {
if !android.InList("libbar.rlib-std", static.Module().(*Module).Properties.AndroidMkRlibs) {
t.Errorf("libbar not present as rlib dependency in static lib")
t.Errorf("libbar not present as rlib dependency in static lib: %s", static.Module().Name())
}
if android.InList("libbar", static.Module().(*Module).Properties.AndroidMkDylibs) {
t.Errorf("libbar present as dynamic dependency in static lib")
t.Errorf("libbar present as dynamic dependency in static lib: %s", static.Module().Name())
}
}
for _, dyn := range []android.TestingModule{libfooDylib, libfooShared} {
if !android.InList("libbar", dyn.Module().(*Module).Properties.AndroidMkDylibs) {
t.Errorf("libbar not present as dynamic dependency in dynamic lib")
t.Errorf("libbar not present as dynamic dependency in dynamic lib: %s", dyn.Module().Name())
}
if android.InList("libbar", dyn.Module().(*Module).Properties.AndroidMkRlibs) {
t.Errorf("libbar present as rlib dependency in dynamic lib")
t.Errorf("libbar present as rlib dependency in dynamic lib: %s", dyn.Module().Name())
}
if !android.InList("librlib_only", dyn.Module().(*Module).Properties.AndroidMkRlibs) {
t.Errorf("librlib_only should be selected by rustlibs as an rlib.")
t.Errorf("librlib_only should be selected by rustlibs as an rlib: %s.", dyn.Module().Name())
}
}
}
@ -375,6 +395,7 @@ func TestLibstdLinkage(t *testing.T) {
libbarShared := ctx.ModuleForTests("libbar", "android_arm64_armv8-a_shared").Module().(*Module)
libbarStatic := ctx.ModuleForTests("libbar", "android_arm64_armv8-a_static").Module().(*Module)
libbarFFIRlib := ctx.ModuleForTests("libbar", "android_arm64_armv8-a_rlib_rlib-std").Module().(*Module)
// prefer_rlib works the same for both rust_library and rust_ffi, so a single check is sufficient here.
libbarRlibStd := ctx.ModuleForTests("libbar.prefer_rlib", "android_arm64_armv8-a_shared").Module().(*Module)
@ -398,6 +419,12 @@ func TestLibstdLinkage(t *testing.T) {
if !android.InList("libfoo.rlib-std", libbarStatic.Properties.AndroidMkRlibs) {
t.Errorf("Device rust_ffi_static does not link dependent rustlib rlib-std variant")
}
if !android.InList("libstd", libbarFFIRlib.Properties.AndroidMkRlibs) {
t.Errorf("Device rust_ffi_rlib does not link libstd as an rlib")
}
if !android.InList("libfoo.rlib-std", libbarFFIRlib.Properties.AndroidMkRlibs) {
t.Errorf("Device rust_ffi_rlib does not link dependent rustlib rlib-std variant")
}
if !android.InList("libstd", libbarRlibStd.Properties.AndroidMkRlibs) {
t.Errorf("rust_ffi with prefer_rlib does not link libstd as an rlib")
}

View file

@ -76,6 +76,7 @@ func (procMacro *procMacroDecorator) compile(ctx ModuleContext, flags Flags, dep
srcPath := crateRootPath(ctx, procMacro)
ret := TransformSrctoProcMacro(ctx, srcPath, deps, flags, outputFile)
procMacro.baseCompiler.unstrippedOutputFile = outputFile
return ret
}

View file

@ -158,6 +158,8 @@ type Module struct {
sourceProvider SourceProvider
subAndroidMkOnce map[SubAndroidMkProvider]bool
exportedLinkDirs []string
// Output file to be installed, may be stripped or unstripped.
outputFile android.OptionalPath
@ -231,8 +233,8 @@ func (mod *Module) SelectedStl() string {
func (mod *Module) NonCcVariants() bool {
if mod.compiler != nil {
if _, ok := mod.compiler.(libraryInterface); ok {
return false
if library, ok := mod.compiler.(libraryInterface); ok {
return library.buildRlib() || library.buildDylib()
}
}
panic(fmt.Errorf("NonCcVariants called on non-library module: %q", mod.BaseModuleName()))
@ -462,6 +464,11 @@ type PathDeps struct {
linkDirs []string
linkObjects []string
// exportedLinkDirs are exported linkDirs for direct rlib dependencies to
// cc_library_static dependants of rlibs.
// Track them separately from linkDirs so superfluous -L flags don't get emitted.
exportedLinkDirs []string
// Used by bindgen modules which call clang
depClangFlags []string
depIncludePaths android.Paths
@ -474,6 +481,9 @@ type PathDeps struct {
// Paths to generated source files
SrcDeps android.Paths
srcProviderFiles android.Paths
// Used by Generated Libraries
depExportedRlibs []cc.RustRlibDep
}
type RustLibraries []RustLibrary
@ -540,6 +550,10 @@ func (mod *Module) VndkVersion() string {
return mod.Properties.VndkVersion
}
func (mod *Module) ExportedCrateLinkDirs() []string {
return mod.exportedLinkDirs
}
func (mod *Module) PreventInstall() bool {
return mod.Properties.PreventInstall
}
@ -654,15 +668,6 @@ func (mod *Module) UnstrippedOutputFile() android.Path {
return nil
}
func (mod *Module) IncludeDirs() android.Paths {
if mod.compiler != nil {
if library, ok := mod.compiler.(*libraryDecorator); ok {
return library.includeDirs
}
}
panic(fmt.Errorf("IncludeDirs called on non-library module: %q", mod.BaseModuleName()))
}
func (mod *Module) SetStatic() {
if mod.compiler != nil {
if library, ok := mod.compiler.(libraryInterface); ok {
@ -911,6 +916,10 @@ func (mod *Module) GenerateAndroidBuildActions(actx android.ModuleContext) {
}
deps := mod.depsToPaths(ctx)
// Export linkDirs for CC rust generatedlibs
mod.exportedLinkDirs = append(mod.exportedLinkDirs, deps.exportedLinkDirs...)
mod.exportedLinkDirs = append(mod.exportedLinkDirs, deps.linkDirs...)
flags := Flags{
Toolchain: toolchain,
}
@ -988,6 +997,9 @@ func (mod *Module) GenerateAndroidBuildActions(actx android.ModuleContext) {
if ctx.Failed() {
return
}
// Export your own directory as a linkDir
mod.exportedLinkDirs = append(mod.exportedLinkDirs, linkPathFromFilePath(mod.OutputFile().Path()))
}
ctx.Phony("rust", ctx.RustModule().OutputFile().Path())
@ -1218,7 +1230,7 @@ func (mod *Module) depsToPaths(ctx android.ModuleContext) PathDeps {
return
}
if rustDep, ok := dep.(*Module); ok && !rustDep.CcLibraryInterface() {
if rustDep, ok := dep.(*Module); ok && !rustDep.Static() && !rustDep.Shared() {
//Handle Rust Modules
makeLibName := rustMakeLibName(ctx, mod, rustDep, depName+rustDep.Properties.RustSubName)
@ -1244,9 +1256,16 @@ func (mod *Module) depsToPaths(ctx android.ModuleContext) PathDeps {
mod.Properties.AndroidMkRlibs = append(mod.Properties.AndroidMkRlibs, makeLibName)
mod.Properties.SnapshotRlibs = append(mod.Properties.SnapshotRlibs, cc.BaseLibName(depName))
// rust_ffi rlibs may export include dirs, so collect those here.
exportedInfo, _ := android.OtherModuleProvider(ctx, dep, cc.FlagExporterInfoProvider)
depPaths.depIncludePaths = append(depPaths.depIncludePaths, exportedInfo.IncludeDirs...)
depPaths.exportedLinkDirs = append(depPaths.exportedLinkDirs, linkPathFromFilePath(rustDep.OutputFile().Path()))
case procMacroDepTag:
directProcMacroDeps = append(directProcMacroDeps, rustDep)
mod.Properties.AndroidMkProcMacroLibs = append(mod.Properties.AndroidMkProcMacroLibs, makeLibName)
// proc_macro link dirs need to be exported, so collect those here.
depPaths.exportedLinkDirs = append(depPaths.exportedLinkDirs, linkPathFromFilePath(rustDep.OutputFile().Path()))
case sourceDepTag:
if _, ok := mod.sourceProvider.(*protobufDecorator); ok {
@ -1276,12 +1295,12 @@ func (mod *Module) depsToPaths(ctx android.ModuleContext) PathDeps {
directSrcProvidersDeps = append(directSrcProvidersDeps, rustDep)
}
exportedInfo, _ := android.OtherModuleProvider(ctx, dep, FlagExporterInfoProvider)
//Append the dependencies exportedDirs, except for proc-macros which target a different arch/OS
if depTag != procMacroDepTag {
exportedInfo, _ := android.OtherModuleProvider(ctx, dep, FlagExporterInfoProvider)
depPaths.linkDirs = append(depPaths.linkDirs, exportedInfo.LinkDirs...)
depPaths.depFlags = append(depPaths.depFlags, exportedInfo.Flags...)
depPaths.linkObjects = append(depPaths.linkObjects, exportedInfo.LinkObjects...)
depPaths.linkDirs = append(depPaths.linkDirs, exportedInfo.LinkDirs...)
}
if depTag == dylibDepTag || depTag == rlibDepTag || depTag == procMacroDepTag {
@ -1291,6 +1310,7 @@ func (mod *Module) depsToPaths(ctx android.ModuleContext) PathDeps {
lib.exportLinkDirs(linkDir)
}
}
if depTag == sourceDepTag {
if _, ok := mod.sourceProvider.(*protobufDecorator); ok && mod.Source() {
if _, ok := rustDep.sourceProvider.(*protobufDecorator); ok {
@ -1555,6 +1575,7 @@ func (mod *Module) DepsMutator(actx android.BottomUpMutatorContext) {
}
rlibDepVariations := commonDepVariations
rlibDepVariations = append(rlibDepVariations, blueprint.Variation{Mutator: "link", Variation: ""})
if lib, ok := mod.compiler.(libraryInterface); !ok || !lib.sysroot() {
rlibDepVariations = append(rlibDepVariations,
@ -1570,6 +1591,8 @@ func (mod *Module) DepsMutator(actx android.BottomUpMutatorContext) {
// dylibs
dylibDepVariations := append(commonDepVariations, blueprint.Variation{Mutator: "rust_libraries", Variation: dylibVariation})
dylibDepVariations = append(dylibDepVariations, blueprint.Variation{Mutator: "link", Variation: ""})
for _, lib := range deps.Dylibs {
actx.AddVariationDependencies(dylibDepVariations, dylibDepTag, lib)
}
@ -1589,7 +1612,7 @@ func (mod *Module) DepsMutator(actx android.BottomUpMutatorContext) {
// otherwise select the rlib variant.
autoDepVariations := append(commonDepVariations,
blueprint.Variation{Mutator: "rust_libraries", Variation: autoDep.variation})
autoDepVariations = append(autoDepVariations, blueprint.Variation{Mutator: "link", Variation: ""})
if actx.OtherModuleDependencyVariantExists(autoDepVariations, lib) {
actx.AddVariationDependencies(autoDepVariations, autoDep.depTag, lib)
@ -1604,7 +1627,11 @@ func (mod *Module) DepsMutator(actx android.BottomUpMutatorContext) {
for _, lib := range deps.Rustlibs {
srcProviderVariations := append(commonDepVariations,
blueprint.Variation{Mutator: "rust_libraries", Variation: "source"})
srcProviderVariations = append(srcProviderVariations, blueprint.Variation{Mutator: "link", Variation: ""})
// Only add rustlib dependencies if they're source providers themselves.
// This is used to track which crate names need to be added to the source generated
// in the rust_protobuf mod.rs.
if actx.OtherModuleDependencyVariantExists(srcProviderVariations, lib) {
actx.AddVariationDependencies(srcProviderVariations, sourceDepTag, lib)
}
@ -1616,7 +1643,7 @@ func (mod *Module) DepsMutator(actx android.BottomUpMutatorContext) {
if deps.Stdlibs != nil {
if mod.compiler.stdLinkage(ctx) == RlibLinkage {
for _, lib := range deps.Stdlibs {
actx.AddVariationDependencies(append(commonDepVariations, []blueprint.Variation{{Mutator: "rust_libraries", Variation: "rlib"}}...),
actx.AddVariationDependencies(append(commonDepVariations, []blueprint.Variation{{Mutator: "rust_libraries", Variation: "rlib"}, {Mutator: "link", Variation: ""}}...),
rlibDepTag, lib)
}
} else {

View file

@ -150,15 +150,11 @@ func TestDepsTracking(t *testing.T) {
host_supported: true,
name: "cc_stubs_dep",
}
rust_ffi_host_static {
cc_library_host_static {
name: "libstatic",
srcs: ["foo.rs"],
crate_name: "static",
}
rust_ffi_host_static {
cc_library_host_static {
name: "libwholestatic",
srcs: ["foo.rs"],
crate_name: "wholestatic",
}
rust_ffi_host_shared {
name: "libshared",
@ -435,6 +431,105 @@ func TestRustAliases(t *testing.T) {
}
}
func TestRustRlibs(t *testing.T) {
ctx := testRust(t, `
rust_ffi_rlib {
name: "libbar",
crate_name: "bar",
srcs: ["src/lib.rs"],
export_include_dirs: ["bar_includes"]
}
rust_ffi_rlib {
name: "libfoo",
crate_name: "foo",
srcs: ["src/lib.rs"],
export_include_dirs: ["foo_includes"]
}
cc_library_shared {
name: "libcc_shared",
srcs:["foo.c"],
static_rlibs: ["libbar"],
}
cc_library_static {
name: "libcc_static",
srcs:["foo.c"],
static_rlibs: ["libfoo"],
}
cc_binary {
name: "ccBin",
srcs:["foo.c"],
static_rlibs: ["libbar"],
static_libs: ["libcc_static"],
}
`)
libbar := ctx.ModuleForTests("libbar", "android_arm64_armv8-a_rlib_rlib-std").Rule("rustc")
libcc_shared_rustc := ctx.ModuleForTests("libcc_shared", "android_arm64_armv8-a_shared").Rule("rustc")
libcc_shared_ld := ctx.ModuleForTests("libcc_shared", "android_arm64_armv8-a_shared").Rule("ld")
libcc_shared_cc := ctx.ModuleForTests("libcc_shared", "android_arm64_armv8-a_shared").Rule("cc")
ccbin_rustc := ctx.ModuleForTests("ccBin", "android_arm64_armv8-a").Rule("rustc")
ccbin_ld := ctx.ModuleForTests("ccBin", "android_arm64_armv8-a").Rule("ld")
ccbin_cc := ctx.ModuleForTests("ccBin", "android_arm64_armv8-a").Rule("cc")
if !strings.Contains(libbar.Args["rustcFlags"], "crate-type=rlib") {
t.Errorf("missing crate-type for static variant, expecting %#v, rustcFlags: %#v", "rlib", libbar.Args["rustcFlags"])
}
// Make sure there's a rustc command, and it's producing a staticlib
if !strings.Contains(libcc_shared_rustc.Args["rustcFlags"], "crate-type=staticlib") {
t.Errorf("missing crate-type for static variant, expecting %#v, rustcFlags: %#v",
"staticlib", libcc_shared_rustc.Args["rustcFlags"])
}
// Make sure the static lib is included in the ld command
if !strings.Contains(libcc_shared_ld.Args["libFlags"], "generated_rust_staticlib/liblibcc_shared_rust_staticlib.a") {
t.Errorf("missing generated static library in linker step libFlags %#v, libFlags: %#v",
"libcc_shared.generated_rust_staticlib.a", libcc_shared_ld.Args["libFlags"])
}
// Make sure the static lib includes are in the cc command
if !strings.Contains(libcc_shared_cc.Args["cFlags"], "-Ibar_includes") {
t.Errorf("missing rlibs includes, expecting %#v, cFlags: %#v",
"-Ibar_includes", libcc_shared_cc.Args["cFlags"])
}
// Make sure there's a rustc command, and it's producing a staticlib
if !strings.Contains(ccbin_rustc.Args["rustcFlags"], "crate-type=staticlib") {
t.Errorf("missing crate-type for static variant, expecting %#v, rustcFlags: %#v", "staticlib", ccbin_rustc.Args["rustcFlags"])
}
// Make sure the static lib is included in the cc command
if !strings.Contains(ccbin_ld.Args["libFlags"], "generated_rust_staticlib/libccBin_rust_staticlib.a") {
t.Errorf("missing generated static library in linker step libFlags, expecting %#v, libFlags: %#v",
"ccBin.generated_rust_staticlib.a", ccbin_ld.Args["libFlags"])
}
// Make sure the static lib includes are in the ld command
if !strings.Contains(ccbin_cc.Args["cFlags"], "-Ibar_includes") {
t.Errorf("missing rlibs includes, expecting %#v, cFlags: %#v",
"-Ibar_includes", ccbin_cc.Args)
}
// Make sure that direct dependencies and indirect dependencies are
// propagating correctly to the generated rlib.
if !strings.Contains(ccbin_rustc.Args["libFlags"], "--extern foo=") {
t.Errorf("Missing indirect dependency libfoo when writing generated Rust staticlib: %#v", ccbin_rustc.Args["libFlags"])
}
if !strings.Contains(ccbin_rustc.Args["libFlags"], "--extern bar=") {
t.Errorf("Missing direct dependency libbar when writing generated Rust staticlib: %#v", ccbin_rustc.Args["libFlags"])
}
// Test indirect includes propagation
if !strings.Contains(ccbin_cc.Args["cFlags"], "-Ifoo_includes") {
t.Errorf("missing rlibs includes, expecting %#v, cFlags: %#v",
"-Ifoo_includes", ccbin_cc.Args)
}
}
func assertString(t *testing.T, got, expected string) {
t.Helper()
if got != expected {

View file

@ -49,16 +49,28 @@ var PrepareForIntegrationTestWithRust = android.GroupFixturePreparers(
func GatherRequiredDepsForTest() string {
bp := `
rust_prebuilt_library {
name: "libstd",
crate_name: "std",
rlib: {
srcs: ["libstd.rlib"],
},
dylib: {
srcs: ["libstd.so"],
},
host_supported: true,
sysroot: true,
name: "libstd",
crate_name: "std",
rlib: {
srcs: ["libstd/libstd.rlib"],
},
dylib: {
srcs: ["libstd/libstd.so"],
},
host_supported: true,
sysroot: true,
}
rust_prebuilt_library {
name: "libcore.sysroot",
crate_name: "core",
rlib: {
srcs: ["libcore/libcore.rlib"],
},
dylib: {
srcs: ["libcore/libcore.so"],
},
host_supported: true,
sysroot: true,
}
//////////////////////////////
// Device module requirements
@ -176,10 +188,12 @@ func registerRequiredBuildComponentsForTest(ctx android.RegistrationContext) {
ctx.RegisterModuleType("rust_fuzz_host", RustFuzzHostFactory)
ctx.RegisterModuleType("rust_ffi", RustFFIFactory)
ctx.RegisterModuleType("rust_ffi_shared", RustFFISharedFactory)
ctx.RegisterModuleType("rust_ffi_static", RustFFIStaticFactory)
ctx.RegisterModuleType("rust_ffi_rlib", RustFFIRlibFactory)
ctx.RegisterModuleType("rust_ffi_static", RustFFIStaticRlibFactory)
ctx.RegisterModuleType("rust_ffi_host", RustFFIHostFactory)
ctx.RegisterModuleType("rust_ffi_host_shared", RustFFISharedHostFactory)
ctx.RegisterModuleType("rust_ffi_host_static", RustFFIStaticHostFactory)
ctx.RegisterModuleType("rust_ffi_host_rlib", RustFFIRlibHostFactory)
ctx.RegisterModuleType("rust_ffi_host_static", RustFFIStaticRlibHostFactory)
ctx.RegisterModuleType("rust_proc_macro", ProcMacroFactory)
ctx.RegisterModuleType("rust_protobuf", RustProtobufFactory)
ctx.RegisterModuleType("rust_protobuf_host", RustProtobufHostFactory)