| // Copyright 2019 The Android Open Source Project |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| package rust |
| |
| import ( |
| "android/soong/cc" |
| "errors" |
| "fmt" |
| "path/filepath" |
| "strings" |
| |
| "github.com/google/blueprint/proptools" |
| |
| "android/soong/android" |
| "android/soong/rust/config" |
| ) |
| |
| type RustLinkage int |
| |
| const ( |
| DefaultLinkage RustLinkage = iota |
| RlibLinkage |
| 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 |
| |
| // 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) |
| } |
| |
| func (compiler *baseCompiler) setNoStdlibs() { |
| compiler.Properties.No_stdlibs = proptools.BoolPtr(true) |
| } |
| |
| func (compiler *baseCompiler) disableLints() { |
| compiler.Properties.Lints = proptools.StringPtr("none") |
| } |
| |
| func NewBaseCompiler(dir, dir64 string, location installLocation) *baseCompiler { |
| return &baseCompiler{ |
| Properties: BaseCompilerProperties{}, |
| dir: dir, |
| dir64: dir64, |
| location: location, |
| } |
| } |
| |
| type installLocation int |
| |
| const ( |
| InstallInSystem installLocation = 0 |
| InstallInData = iota |
| |
| incorrectSourcesError = "srcs can only contain one path for a rust file and source providers prefixed by \":\"" |
| genSubDir = "out/" |
| ) |
| |
| type BaseCompilerProperties struct { |
| // path to the source file that is the main entry point of the program (e.g. main.rs or lib.rs). |
| // Only a single source file can be defined. Modules which generate source can be included by prefixing |
| // the module name with ":", for example ":libfoo_bindgen" |
| // |
| // 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 |
| // depending on the module's location), "android" (for the strictest |
| // lint set that applies to all Android platform code), "vendor" (for |
| // a relaxed set) and "none" (for ignoring all lint warnings and |
| // errors). The default value is "default". |
| Lints *string |
| |
| // flags to pass to rustc. To enable configuration options or features, use the "cfgs" or "features" properties. |
| Flags []string `android:"arch_variant"` |
| |
| // 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 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 |
| Proc_macros []string `android:"arch_variant"` |
| |
| // list of C shared library dependencies |
| Shared_libs []string `android:"arch_variant"` |
| |
| // list of C static library dependencies. These dependencies do not normally propagate to dependents |
| // and may need to be redeclared. See whole_static_libs for bundling static dependencies into a library. |
| Static_libs []string `android:"arch_variant"` |
| |
| // Similar to static_libs, but will bundle the static library dependency into a library. This is helpful |
| // to avoid having to redeclare the dependency for dependents of this library, but in some cases may also |
| // result in bloat if multiple dependencies all include the same static library whole. |
| // |
| // The common use case for this is when the static library is unlikely to be a dependency of other modules to avoid |
| // having to redeclare the static library dependency for every dependent module. |
| // If you are not sure what to, for rust_library modules most static dependencies should go in static_libraries, |
| // and for rust_ffi modules most static dependencies should go into whole_static_libraries. |
| // |
| // For rust_ffi static variants, these libraries will be included in the resulting static library archive. |
| // |
| // For rust_library rlib variants, these libraries will be bundled into the resulting rlib library. This will |
| // include all of the static libraries symbols in any dylibs or binaries which use this rlib as well. |
| Whole_static_libs []string `android:"arch_variant"` |
| |
| // list of Rust system library dependencies. |
| // |
| // This is usually only needed when `no_stdlibs` is true, in which case it can be used to depend on system crates |
| // like `core` and `alloc`. |
| Stdlibs []string `android:"arch_variant"` |
| |
| // crate name, required for modules which produce Rust libraries: rust_library, rust_ffi and SourceProvider |
| // modules which create library variants (rust_bindgen). This must be the expected extern crate name used in |
| // source, and is required to conform to an enforced format matching library output files (if the output file is |
| // lib<someName><suffix>, the crate_name property must be <someName>). |
| Crate_name string `android:"arch_variant"` |
| |
| // list of features to enable for this crate |
| 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"` |
| |
| // specific rust edition that should be used if the default version is not desired |
| Edition *string `android:"arch_variant"` |
| |
| // sets name of the output |
| Stem *string `android:"arch_variant"` |
| |
| // append to name of output |
| Suffix *string `android:"arch_variant"` |
| |
| // install to a subdirectory of the default install path for the module |
| Relative_install_path *string `android:"arch_variant"` |
| |
| // whether to suppress inclusion of standard crates - defaults to false |
| 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. |
| // Note: This is the default behavior for host targets. |
| // |
| // This is primarily meant for rust_binary and rust_ffi modules where the default |
| // linkage of libstd might need to be overridden in some use cases. This should |
| // generally be avoided with other module types since it may cause collisions at |
| // linkage if all dependencies of the root binary module do not link against libstd |
| // the same way. |
| Prefer_rlib *bool `android:"arch_variant"` |
| |
| // Enables emitting certain Cargo environment variables. Only intended to be used for compatibility purposes. |
| // Will set CARGO_CRATE_NAME to the crate_name property's value. |
| // Will set CARGO_BIN_NAME to the output filename value without the extension. |
| Cargo_env_compat *bool |
| |
| // If cargo_env_compat is true, sets the CARGO_PKG_VERSION env var to this value. |
| Cargo_pkg_version *string |
| } |
| |
| type baseCompiler struct { |
| Properties BaseCompilerProperties |
| |
| // Install related |
| dir string |
| dir64 string |
| subDir string |
| relative string |
| path android.InstallPath |
| location installLocation |
| sanitize *sanitize |
| |
| distFile android.OptionalPath |
| |
| installDeps android.InstallPaths |
| |
| // unstripped output file. |
| unstrippedOutputFile android.Path |
| |
| // stripped output file. |
| strippedOutputFile android.OptionalPath |
| |
| // If a crate has a source-generated dependency, a copy of the source file |
| // will be available in cargoOutDir (equivalent to Cargo OUT_DIR). |
| // 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 |
| } |
| |
| func (compiler *baseCompiler) SetDisabled() { |
| panic("baseCompiler does not implement SetDisabled()") |
| } |
| |
| func (compiler *baseCompiler) noStdlibs() bool { |
| return Bool(compiler.Properties.No_stdlibs) |
| } |
| |
| func (compiler *baseCompiler) coverageOutputZipPath() android.OptionalPath { |
| panic("baseCompiler does not implement coverageOutputZipPath()") |
| } |
| |
| 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() { |
| return RlibLinkage |
| } else if ctx.Device() { |
| return DylibLinkage |
| } else { |
| return RlibLinkage |
| } |
| } |
| |
| var _ compiler = (*baseCompiler)(nil) |
| |
| func (compiler *baseCompiler) inData() bool { |
| return compiler.location == InstallInData |
| } |
| |
| func (compiler *baseCompiler) compilerProps() []interface{} { |
| return []interface{}{&compiler.Properties} |
| } |
| |
| func (compiler *baseCompiler) cfgsToFlags() []string { |
| flags := []string{} |
| for _, cfg := range compiler.Properties.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.features() { |
| flags = append(flags, "--cfg 'feature=\""+feature+"\"'") |
| } |
| |
| return flags |
| } |
| |
| func (compiler *baseCompiler) featureFlags(ctx ModuleContext, flags Flags) Flags { |
| flags.RustFlags = append(flags.RustFlags, compiler.featuresToFlags()...) |
| flags.RustdocFlags = append(flags.RustdocFlags, compiler.featuresToFlags()...) |
| |
| 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") |
| } |
| } |
| |
| flags.RustFlags = append(flags.RustFlags, compiler.cfgsToFlags()...) |
| flags.RustdocFlags = append(flags.RustdocFlags, compiler.cfgsToFlags()...) |
| return flags |
| } |
| |
| func (compiler *baseCompiler) compilerFlags(ctx ModuleContext, flags Flags) Flags { |
| |
| lintFlags, err := config.RustcLintsForDir(ctx.ModuleDir(), compiler.Properties.Lints) |
| if err != nil { |
| ctx.PropertyErrorf("lints", err.Error()) |
| } |
| |
| // linkage-related flags are disallowed. |
| for _, s := range compiler.Properties.Ld_flags { |
| if strings.HasPrefix(s, "-Wl,-l") || strings.HasPrefix(s, "-Wl,-L") { |
| ctx.PropertyErrorf("ld_flags", "'-Wl,-l' and '-Wl,-L' flags cannot be manually specified") |
| } |
| } |
| for _, s := range compiler.Properties.Flags { |
| if strings.HasPrefix(s, "-l") || strings.HasPrefix(s, "-L") { |
| ctx.PropertyErrorf("flags", "'-l' and '-L' flags cannot be manually specified") |
| } |
| if strings.HasPrefix(s, "--extern") { |
| ctx.PropertyErrorf("flags", "'--extern' flag cannot be manually specified") |
| } |
| if strings.HasPrefix(s, "-Clink-args=") || strings.HasPrefix(s, "-C link-args=") { |
| ctx.PropertyErrorf("flags", "'-C link-args' flag cannot be manually specified") |
| } |
| } |
| |
| flags.RustFlags = append(flags.RustFlags, lintFlags) |
| flags.RustFlags = append(flags.RustFlags, compiler.Properties.Flags...) |
| 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 |
| } |
| |
| func (compiler *baseCompiler) compile(ctx ModuleContext, flags Flags, deps PathDeps) buildOutput { |
| panic(fmt.Errorf("baseCrater doesn't know how to crate things!")) |
| } |
| |
| func (compiler *baseCompiler) rustdoc(ctx ModuleContext, flags Flags, |
| deps PathDeps) android.OptionalPath { |
| |
| return android.OptionalPath{} |
| } |
| |
| func (compiler *baseCompiler) initialize(ctx ModuleContext) { |
| 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.cachedCargoOutDir) |
| } |
| |
| func (compiler *baseCompiler) cargoEnvCompat() bool { |
| return Bool(compiler.Properties.Cargo_env_compat) |
| } |
| |
| func (compiler *baseCompiler) cargoPkgVersion() string { |
| return String(compiler.Properties.Cargo_pkg_version) |
| } |
| |
| func (compiler *baseCompiler) unstrippedOutputFilePath() android.Path { |
| return compiler.unstrippedOutputFile |
| } |
| |
| func (compiler *baseCompiler) strippedOutputFilePath() android.OptionalPath { |
| return compiler.strippedOutputFile |
| } |
| |
| func (compiler *baseCompiler) compilerDeps(ctx DepsContext, deps Deps) Deps { |
| deps.Rlibs = append(deps.Rlibs, compiler.Properties.Rlibs...) |
| 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...) |
| deps.WholeStaticLibs = append(deps.WholeStaticLibs, compiler.Properties.Whole_static_libs...) |
| deps.SharedLibs = append(deps.SharedLibs, compiler.Properties.Shared_libs...) |
| deps.Stdlibs = append(deps.Stdlibs, compiler.Properties.Stdlibs...) |
| |
| if !Bool(compiler.Properties.No_stdlibs) { |
| for _, stdlib := range config.Stdlibs { |
| // If we're building for the build host, use the prebuilt stdlibs, unless the host |
| // is linux_bionic which doesn't have prebuilts. |
| if ctx.Host() && !ctx.Target().HostCross && ctx.Target().Os != android.LinuxBionic { |
| stdlib = "prebuilt_" + stdlib |
| } |
| deps.Stdlibs = append(deps.Stdlibs, stdlib) |
| } |
| } |
| return deps |
| } |
| |
| func bionicDeps(ctx DepsContext, deps Deps, static bool) Deps { |
| bionicLibs := []string{} |
| bionicLibs = append(bionicLibs, "liblog") |
| bionicLibs = append(bionicLibs, "libc") |
| bionicLibs = append(bionicLibs, "libm") |
| bionicLibs = append(bionicLibs, "libdl") |
| |
| if static { |
| deps.StaticLibs = append(deps.StaticLibs, bionicLibs...) |
| } else { |
| deps.SharedLibs = append(deps.SharedLibs, bionicLibs...) |
| } |
| if ctx.RustModule().StaticExecutable() { |
| deps.StaticLibs = append(deps.StaticLibs, "libunwind") |
| } |
| if libRuntimeBuiltins := config.BuiltinsRuntimeLibrary(ctx.toolchain()); libRuntimeBuiltins != "" { |
| deps.StaticLibs = append(deps.StaticLibs, libRuntimeBuiltins) |
| } |
| return deps |
| } |
| |
| func muslDeps(ctx DepsContext, deps Deps, static bool) Deps { |
| muslLibs := []string{"libc_musl"} |
| if static { |
| deps.StaticLibs = append(deps.StaticLibs, muslLibs...) |
| } else { |
| deps.SharedLibs = append(deps.SharedLibs, muslLibs...) |
| } |
| if libRuntimeBuiltins := config.BuiltinsRuntimeLibrary(ctx.toolchain()); libRuntimeBuiltins != "" { |
| deps.StaticLibs = append(deps.StaticLibs, libRuntimeBuiltins) |
| } |
| |
| return deps |
| } |
| |
| func (compiler *baseCompiler) crateName() string { |
| return compiler.Properties.Crate_name |
| } |
| |
| func (compiler *baseCompiler) everInstallable() bool { |
| // Most modules are installable, so return true by default. |
| return true |
| } |
| |
| func (compiler *baseCompiler) installDir(ctx ModuleContext) android.InstallPath { |
| dir := compiler.dir |
| if ctx.toolchain().Is64Bit() && compiler.dir64 != "" { |
| dir = compiler.dir64 |
| } |
| if ctx.Target().NativeBridge == android.NativeBridgeEnabled { |
| dir = filepath.Join(dir, ctx.Target().NativeBridgeRelativePath) |
| } |
| if !ctx.Host() && ctx.Config().HasMultilibConflict(ctx.Arch().ArchType) { |
| dir = filepath.Join(dir, ctx.Arch().ArchType.String()) |
| } |
| |
| if compiler.location == InstallInData && ctx.RustModule().InVendorOrProduct() { |
| if ctx.RustModule().InProduct() { |
| dir = filepath.Join(dir, "product") |
| } else if ctx.RustModule().InVendor() { |
| dir = filepath.Join(dir, "vendor") |
| } else { |
| ctx.ModuleErrorf("Unknown data+VNDK installation kind") |
| } |
| } |
| |
| return android.PathForModuleInstall(ctx, dir, compiler.subDir, |
| compiler.relativeInstallPath(), compiler.relative) |
| } |
| |
| func (compiler *baseCompiler) nativeCoverage() bool { |
| return false |
| } |
| |
| func (compiler *baseCompiler) install(ctx ModuleContext) { |
| path := ctx.RustModule().OutputFile() |
| 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 { |
| return compiler.getStemWithoutSuffix(ctx) + String(compiler.Properties.Suffix) |
| } |
| |
| func (compiler *baseCompiler) getStemWithoutSuffix(ctx BaseModuleContext) string { |
| stem := ctx.ModuleName() |
| if String(compiler.Properties.Stem) != "" { |
| stem = String(compiler.Properties.Stem) |
| } |
| |
| return stem |
| } |
| |
| func (compiler *baseCompiler) relativeInstallPath() string { |
| return String(compiler.Properties.Relative_install_path) |
| } |
| |
| 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. |
| numSrcs := 0 |
| srcIndex := 0 |
| for i, s := range srcs { |
| if android.SrcIsModule(s) == "" { |
| numSrcs++ |
| srcIndex = i |
| } |
| } |
| if numSrcs > 1 { |
| 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 { |
| return nil, errors.New("main source file must be the first in srcs") |
| } else if numSrcs > 1 { |
| 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) |
| if len(paths) == 0 { |
| return nil, errors.New("srcs must not be empty") |
| } |
| return paths[srcIndex], nil |
| } |