| // 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 getDenyWarnings(compiler *baseCompiler) bool { |
| return BoolDefault(compiler.Properties.Deny_warnings, config.DefaultDenyWarnings) |
| } |
| |
| 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 |
| ) |
| |
| type BaseCompilerProperties struct { |
| // whether to pass "-D warnings" to rustc. Defaults to true. |
| Deny_warnings *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 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 |
| pathDeps android.Paths |
| rustFlagsDeps android.Paths |
| linkFlagsDeps android.Paths |
| flags string |
| linkFlags string |
| depFlags []string |
| linkDirs []string |
| edition string |
| src android.Path //rustc takes a single src file |
| |
| // Install related |
| dir string |
| dir64 string |
| subDir string |
| relative string |
| path android.InstallPath |
| location installLocation |
| } |
| |
| 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 getDenyWarnings(compiler) { |
| flags.RustFlags = append(flags.RustFlags, "-D warnings") |
| } |
| 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.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 host, use the compiler's stdlibs |
| if ctx.Host() { |
| stdlib = stdlib + "_" + ctx.toolchain().RustTriple() |
| } |
| |
| // This check is technically insufficient - on the host, where |
| // static linking is the default, if one of our static |
| // dependencies uses a dynamic library, we need to dynamically |
| // link the stdlib as well. |
| if (len(deps.Dylibs) > 0) || (!ctx.Host()) { |
| // Dynamically linked stdlib |
| deps.Dylibs = append(deps.Dylibs, stdlib) |
| } |
| } |
| } |
| return deps |
| } |
| |
| func (compiler *baseCompiler) bionicDeps(ctx DepsContext, 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) 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.baseModuleName() |
| 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 srcPathFromModuleSrcs(ctx ModuleContext, srcs []string) android.Path { |
| srcPaths := android.PathsForModuleSrc(ctx, srcs) |
| if len(srcPaths) != 1 { |
| ctx.PropertyErrorf("srcs", "srcs can only contain one path for rust modules") |
| } |
| return srcPaths[0] |
| } |