// 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 ( "fmt" "path/filepath" "github.com/google/blueprint/proptools" "android/soong/android" "android/soong/rust/config" ) func getEdition(compiler *baseCompiler) string { return proptools.StringDefault(compiler.Properties.Edition, config.DefaultEdition) } func (compiler *baseCompiler) setNoStdlibs() { compiler.Properties.No_stdlibs = proptools.BoolPtr(true) } 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 \":\"" ) type BaseCompilerProperties struct { // path to the source file that is the main entry point of the program (e.g. main.rs or lib.rs) Srcs []string `android:"path,arch_variant"` // whether to suppress the standard lint flags - default to false No_lint *bool // flags to pass to rustc Flags []string `android:"path,arch_variant"` // flags to pass to the linker Ld_flags []string `android:"path,arch_variant"` // 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 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 Static_libs []string `android:"arch_variant"` // crate name, required for libraries. This must be the expected extern crate name used in source Crate_name string `android:"arch_variant"` // list of features to enable for this crate Features []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 } type baseCompiler struct { Properties BaseCompilerProperties coverageFile android.Path //rustc generates a single gcno file // Install related dir string dir64 string subDir string relative string path android.InstallPath location installLocation coverageOutputZipFile android.OptionalPath unstrippedOutputFile android.Path distFile android.OptionalPath } func (compiler *baseCompiler) coverageOutputZipPath() android.OptionalPath { panic("baseCompiler does not implement coverageOutputZipPath()") } 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) featuresToFlags(features []string) []string { flags := []string{} for _, feature := range features { flags = append(flags, "--cfg 'feature=\""+feature+"\"'") } return flags } func (compiler *baseCompiler) compilerFlags(ctx ModuleContext, flags Flags) Flags { if !Bool(compiler.Properties.No_lint) { flags.RustFlags = append(flags.RustFlags, config.RustcLintsForDir(ctx.ModuleDir())) } flags.RustFlags = append(flags.RustFlags, compiler.Properties.Flags...) flags.RustFlags = append(flags.RustFlags, compiler.featuresToFlags(compiler.Properties.Features)...) flags.RustFlags = append(flags.RustFlags, "--edition="+getEdition(compiler)) 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()) if ctx.Host() && !ctx.Windows() { rpath_prefix := `\$$ORIGIN/` if ctx.Darwin() { rpath_prefix = "@loader_path/" } var rpath string if ctx.toolchain().Is64Bit() { rpath = "lib64" } else { rpath = "lib" } flags.LinkFlags = append(flags.LinkFlags, "-Wl,-rpath,"+rpath_prefix+rpath) flags.LinkFlags = append(flags.LinkFlags, "-Wl,-rpath,"+rpath_prefix+"../"+rpath) } return flags } func (compiler *baseCompiler) compile(ctx ModuleContext, flags Flags, deps PathDeps) android.Path { panic(fmt.Errorf("baseCrater doesn't know how to crate things!")) } 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...) deps.SharedLibs = append(deps.SharedLibs, compiler.Properties.Shared_libs...) if !Bool(compiler.Properties.No_stdlibs) { for _, stdlib := range config.Stdlibs { // If we're building for the primary host target, use the compiler's stdlibs if ctx.Host() && ctx.TargetPrimary() { stdlib = stdlib + "_" + ctx.toolchain().RustTriple() } deps.Rustlibs = append(deps.Rustlibs, stdlib) } } return deps } func bionicDeps(deps Deps) Deps { deps.SharedLibs = append(deps.SharedLibs, "liblog") deps.SharedLibs = append(deps.SharedLibs, "libc") deps.SharedLibs = append(deps.SharedLibs, "libm") deps.SharedLibs = append(deps.SharedLibs, "libdl") //TODO(b/141331117) libstd requires libgcc on Android deps.StaticLibs = append(deps.StaticLibs, "libgcc") return deps } func (compiler *baseCompiler) crateName() string { return compiler.Properties.Crate_name } 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()) } return android.PathForModuleInstall(ctx, dir, compiler.subDir, compiler.relativeInstallPath(), compiler.relative) } func (compiler *baseCompiler) nativeCoverage() bool { return false } func (compiler *baseCompiler) install(ctx ModuleContext, file android.Path) { compiler.path = ctx.InstallFile(compiler.installDir(ctx), file.Base(), file) } 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) } // 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) { // 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 { ctx.PropertyErrorf("srcs", incorrectSourcesError) } if srcIndex != 0 { ctx.PropertyErrorf("srcs", "main source file must be the first in srcs") } paths := android.PathsForModuleSrc(ctx, srcs) return paths[srcIndex], paths[1:] }