platform_build_soong/rust/compiler.go

247 lines
7.6 KiB
Go

// 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) *baseCompiler {
return &baseCompiler{
Properties: BaseCompilerProperties{},
dir: dir,
dir64: dir64,
}
}
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
}
var _ compiler = (*baseCompiler)(nil)
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.Host() || ctx.Target().NativeBridge == android.NativeBridgeEnabled {
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]
}