summaryrefslogtreecommitdiff
path: root/rust/compiler.go
diff options
context:
space:
mode:
Diffstat (limited to 'rust/compiler.go')
-rw-r--r--rust/compiler.go246
1 files changed, 200 insertions, 46 deletions
diff --git a/rust/compiler.go b/rust/compiler.go
index 06ae12f79..a2546a194 100644
--- a/rust/compiler.go
+++ b/rust/compiler.go
@@ -16,6 +16,7 @@ package rust
import (
"android/soong/cc"
+ "errors"
"fmt"
"path/filepath"
"strings"
@@ -34,6 +35,51 @@ const (
DylibLinkage
)
+type compiler interface {
+ initialize(ctx ModuleContext)
+ compilerFlags(ctx ModuleContext, flags Flags) Flags
+ cfgFlags(ctx ModuleContext, flags Flags) Flags
+ featureFlags(ctx ModuleContext, flags Flags) Flags
+ compilerProps() []interface{}
+ compile(ctx ModuleContext, flags Flags, deps PathDeps) buildOutput
+ compilerDeps(ctx DepsContext, deps Deps) Deps
+ crateName() string
+ edition() string
+ features() []string
+ rustdoc(ctx ModuleContext, flags Flags, deps PathDeps) android.OptionalPath
+ Thinlto() bool
+
+ // Output directory in which source-generated code from dependencies is
+ // copied. This is equivalent to Cargo's OUT_DIR variable.
+ cargoOutDir() android.OptionalPath
+
+ // cargoPkgVersion returns the value of the Cargo_pkg_version property.
+ cargoPkgVersion() string
+
+ // cargoEnvCompat returns whether Cargo environment variables should be used.
+ cargoEnvCompat() bool
+
+ inData() bool
+ install(ctx ModuleContext)
+ relativeInstallPath() string
+ everInstallable() bool
+
+ nativeCoverage() bool
+
+ Disabled() bool
+ SetDisabled()
+
+ stdLinkage(ctx *depsContext) RustLinkage
+ noStdlibs() bool
+
+ unstrippedOutputFilePath() android.Path
+ strippedOutputFilePath() android.OptionalPath
+
+ checkedCrateRootPath() (android.Path, error)
+
+ Aliases() map[string]string
+}
+
func (compiler *baseCompiler) edition() string {
return proptools.StringDefault(compiler.Properties.Edition, config.DefaultEdition)
}
@@ -73,6 +119,15 @@ type BaseCompilerProperties struct {
// If no source file is defined, a single generated source module can be defined to be used as the main source.
Srcs []string `android:"path,arch_variant"`
+ // Entry point that is passed to rustc to begin the compilation. E.g. main.rs or lib.rs.
+ // When this property is set,
+ // * sandboxing is enabled for this module, and
+ // * the srcs attribute is interpreted as a list of all source files potentially
+ // used in compilation, including the entrypoint, and
+ // * compile_data can be used to add additional files used in compilation that
+ // not directly used as source files.
+ Crate_root *string `android:"path,arch_variant"`
+
// name of the lint set that should be used to validate this module.
//
// Possible values are "default" (for using a sensible set of lints
@@ -88,13 +143,17 @@ type BaseCompilerProperties struct {
// flags to pass to the linker
Ld_flags []string `android:"arch_variant"`
+ // Rust crate dependencies to rename. Each entry should be a string of the form "dependencyname:alias".
+ //
+ // "dependencyname" here should be the name of the crate, not the Android module. This is
+ // equivalent to writing `alias = { package = "dependencyname" }` in a `Cargo.toml`.
+ Aliases []string
+
// list of rust rlib crate dependencies
Rlibs []string `android:"arch_variant"`
- // list of rust dylib crate dependencies
- Dylibs []string `android:"arch_variant"`
-
- // list of rust automatic crate dependencies
+ // list of rust automatic crate dependencies.
+ // Rustlibs linkage is rlib for host targets and dylib for device targets.
Rustlibs []string `android:"arch_variant"`
// list of rust proc_macro crate dependencies
@@ -138,7 +197,7 @@ type BaseCompilerProperties struct {
Features []string `android:"arch_variant"`
// list of configuration options to enable for this crate. To enable features, use the "features" property.
- Cfgs []string `android:"arch_variant"`
+ Cfgs proptools.Configurable[[]string] `android:"arch_variant"`
// specific rust edition that should be used if the default version is not desired
Edition *string `android:"arch_variant"`
@@ -153,7 +212,7 @@ type BaseCompilerProperties struct {
Relative_install_path *string `android:"arch_variant"`
// whether to suppress inclusion of standard crates - defaults to false
- No_stdlibs *bool
+ No_stdlibs *bool `android:"arch_variant"`
// Change the rustlibs linkage to select rlib linkage by default for device targets.
// Also link libstd as an rlib as well on device targets.
@@ -173,6 +232,15 @@ type BaseCompilerProperties struct {
// If cargo_env_compat is true, sets the CARGO_PKG_VERSION env var to this value.
Cargo_pkg_version *string
+
+ // Control whether LTO is used for the final (Rust) linkage. This does not impact
+ // cross-language LTO.
+ Lto struct {
+ // Whether thin LTO should be enabled. By default this is true.
+ // LTO provides such a large code size benefit for Rust, this should always
+ // be enabled for production builds unless there's a clear need to disable it.
+ Thin *bool `android:"arch_variant"`
+ } `android:"arch_variant"`
}
type baseCompiler struct {
@@ -189,6 +257,8 @@ type baseCompiler struct {
distFile android.OptionalPath
+ installDeps android.InstallPaths
+
// unstripped output file.
unstrippedOutputFile android.Path
@@ -197,13 +267,27 @@ type baseCompiler struct {
// If a crate has a source-generated dependency, a copy of the source file
// will be available in cargoOutDir (equivalent to Cargo OUT_DIR).
- cargoOutDir android.ModuleOutPath
+ // This is stored internally because it may not be available during
+ // singleton-generation passes like rustdoc/rust_project.json, but should
+ // be stashed during initial generation.
+ cachedCargoOutDir android.ModuleOutPath
+ // Calculated crate root cached internally because ModuleContext is not
+ // available to singleton targets like rustdoc/rust_project.json
+ cachedCrateRootPath android.Path
+ // If cachedCrateRootPath is nil after initialization, this will contain
+ // an explanation of why
+ cachedCrateRootError error
}
func (compiler *baseCompiler) Disabled() bool {
return false
}
+// Thin LTO is enabled by default.
+func (compiler *baseCompiler) Thinlto() bool {
+ return BoolDefault(compiler.Properties.Lto.Thin, true)
+}
+
func (compiler *baseCompiler) SetDisabled() {
panic("baseCompiler does not implement SetDisabled()")
}
@@ -220,6 +304,18 @@ func (compiler *baseCompiler) preferRlib() bool {
return Bool(compiler.Properties.Prefer_rlib)
}
+func (compiler *baseCompiler) Aliases() map[string]string {
+ aliases := map[string]string{}
+ for _, entry := range compiler.Properties.Aliases {
+ dep, alias, found := strings.Cut(entry, ":")
+ if !found {
+ panic(fmt.Errorf("invalid aliases entry %q missing ':'", entry))
+ }
+ aliases[dep] = alias
+ }
+ return aliases
+}
+
func (compiler *baseCompiler) stdLinkage(ctx *depsContext) RustLinkage {
// For devices, we always link stdlibs in as dylibs by default.
if compiler.preferRlib() {
@@ -241,18 +337,22 @@ func (compiler *baseCompiler) compilerProps() []interface{} {
return []interface{}{&compiler.Properties}
}
-func (compiler *baseCompiler) cfgsToFlags() []string {
- flags := []string{}
- for _, cfg := range compiler.Properties.Cfgs {
+func cfgsToFlags(cfgs []string) []string {
+ flags := make([]string, 0, len(cfgs))
+ for _, cfg := range cfgs {
flags = append(flags, "--cfg '"+cfg+"'")
}
return flags
}
+func (compiler *baseCompiler) features() []string {
+ return compiler.Properties.Features
+}
+
func (compiler *baseCompiler) featuresToFlags() []string {
flags := []string{}
- for _, feature := range compiler.Properties.Features {
+ for _, feature := range compiler.features() {
flags = append(flags, "--cfg 'feature=\""+feature+"\"'")
}
@@ -266,23 +366,62 @@ func (compiler *baseCompiler) featureFlags(ctx ModuleContext, flags Flags) Flags
return flags
}
-func (compiler *baseCompiler) cfgFlags(ctx ModuleContext, flags Flags) Flags {
- if ctx.RustModule().UseVndk() {
- 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())
+
+ cfgFlags := cfgsToFlags(compiler.Properties.Cfgs.GetOrDefault(ctx, nil))
+ flags.RustFlags = append(flags.RustFlags, cfgFlags...)
+ flags.RustdocFlags = append(flags.RustdocFlags, cfgFlags...)
+
+ 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())
@@ -311,14 +450,6 @@ 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)...)
- }
return flags
}
@@ -334,18 +465,24 @@ func (compiler *baseCompiler) rustdoc(ctx ModuleContext, flags Flags,
}
func (compiler *baseCompiler) initialize(ctx ModuleContext) {
- compiler.cargoOutDir = android.PathForModuleOut(ctx, genSubDir)
+ compiler.cachedCargoOutDir = android.PathForModuleOut(ctx, genSubDir)
+ if compiler.Properties.Crate_root == nil {
+ compiler.cachedCrateRootPath, compiler.cachedCrateRootError = srcPathFromModuleSrcs(ctx, compiler.Properties.Srcs)
+ } else {
+ compiler.cachedCrateRootPath = android.PathForModuleSrc(ctx, *compiler.Properties.Crate_root)
+ compiler.cachedCrateRootError = nil
+ }
}
-func (compiler *baseCompiler) CargoOutDir() android.OptionalPath {
- return android.OptionalPathForPath(compiler.cargoOutDir)
+func (compiler *baseCompiler) cargoOutDir() android.OptionalPath {
+ return android.OptionalPathForPath(compiler.cachedCargoOutDir)
}
-func (compiler *baseCompiler) CargoEnvCompat() bool {
+func (compiler *baseCompiler) cargoEnvCompat() bool {
return Bool(compiler.Properties.Cargo_env_compat)
}
-func (compiler *baseCompiler) CargoPkgVersion() string {
+func (compiler *baseCompiler) cargoPkgVersion() string {
return String(compiler.Properties.Cargo_pkg_version)
}
@@ -359,7 +496,6 @@ func (compiler *baseCompiler) strippedOutputFilePath() android.OptionalPath {
func (compiler *baseCompiler) compilerDeps(ctx DepsContext, deps Deps) Deps {
deps.Rlibs = append(deps.Rlibs, compiler.Properties.Rlibs...)
- deps.Dylibs = append(deps.Dylibs, compiler.Properties.Dylibs...)
deps.Rustlibs = append(deps.Rustlibs, compiler.Properties.Rustlibs...)
deps.ProcMacros = append(deps.ProcMacros, compiler.Properties.Proc_macros...)
deps.StaticLibs = append(deps.StaticLibs, compiler.Properties.Static_libs...)
@@ -436,7 +572,7 @@ func (compiler *baseCompiler) installDir(ctx ModuleContext) android.InstallPath
dir = filepath.Join(dir, ctx.Arch().ArchType.String())
}
- if compiler.location == InstallInData && ctx.RustModule().UseVndk() {
+ if compiler.location == InstallInData && ctx.RustModule().InVendorOrProduct() {
if ctx.RustModule().InProduct() {
dir = filepath.Join(dir, "product")
} else if ctx.RustModule().InVendor() {
@@ -456,14 +592,19 @@ func (compiler *baseCompiler) nativeCoverage() bool {
func (compiler *baseCompiler) install(ctx ModuleContext) {
path := ctx.RustModule().OutputFile()
- compiler.path = ctx.InstallFile(compiler.installDir(ctx), path.Path().Base(), path.Path())
+ compiler.path = ctx.InstallFile(compiler.installDir(ctx), path.Path().Base(), path.Path(), compiler.installDeps...)
+}
+
+func (compiler *baseCompiler) installTestData(ctx ModuleContext, data []android.DataPath) {
+ installedData := ctx.InstallTestData(compiler.installDir(ctx), data)
+ 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)
@@ -476,12 +617,20 @@ func (compiler *baseCompiler) relativeInstallPath() string {
return String(compiler.Properties.Relative_install_path)
}
-// Returns the Path for the main source file along with Paths for generated source files from modules listed in srcs.
-func srcPathFromModuleSrcs(ctx ModuleContext, srcs []string) (android.Path, android.Paths) {
- if len(srcs) == 0 {
- ctx.PropertyErrorf("srcs", "srcs must not be empty")
+func (compiler *baseCompiler) checkedCrateRootPath() (android.Path, error) {
+ return compiler.cachedCrateRootPath, compiler.cachedCrateRootError
+}
+
+func crateRootPath(ctx ModuleContext, compiler compiler) android.Path {
+ root, err := compiler.checkedCrateRootPath()
+ if err != nil {
+ ctx.PropertyErrorf("srcs", err.Error())
}
+ return root
+}
+// Returns the Path for the main source file along with Paths for generated source files from modules listed in srcs.
+func srcPathFromModuleSrcs(ctx ModuleContext, srcs []string) (android.Path, error) {
// The srcs can contain strings with prefix ":".
// They are dependent modules of this module, with android.SourceDepTag.
// They are not the main source file compiled by rustc.
@@ -494,17 +643,22 @@ func srcPathFromModuleSrcs(ctx ModuleContext, srcs []string) (android.Path, andr
}
}
if numSrcs > 1 {
- ctx.PropertyErrorf("srcs", incorrectSourcesError)
+ return nil, errors.New(incorrectSourcesError)
}
// If a main source file is not provided we expect only a single SourceProvider module to be defined
// within srcs, with the expectation that the first source it provides is the entry point.
if srcIndex != 0 {
- ctx.PropertyErrorf("srcs", "main source file must be the first in srcs")
+ return nil, errors.New("main source file must be the first in srcs")
} else if numSrcs > 1 {
- ctx.PropertyErrorf("srcs", "only a single generated source module can be defined without a main source file.")
+ return nil, errors.New("only a single generated source module can be defined without a main source file.")
}
+ // TODO: b/297264540 - once all modules are sandboxed, we need to select the proper
+ // entry point file from Srcs rather than taking the first one
paths := android.PathsForModuleSrc(ctx, srcs)
- return paths[srcIndex], paths[1:]
+ if len(paths) == 0 {
+ return nil, errors.New("srcs must not be empty")
+ }
+ return paths[srcIndex], nil
}