1// Copyright 2019 The Android Open Source Project 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15package rust 16 17import ( 18 "fmt" 19 "path/filepath" 20 21 "github.com/google/blueprint/proptools" 22 23 "android/soong/android" 24 "android/soong/rust/config" 25) 26 27func getEdition(compiler *baseCompiler) string { 28 return proptools.StringDefault(compiler.Properties.Edition, config.DefaultEdition) 29} 30 31func getDenyWarnings(compiler *baseCompiler) bool { 32 return BoolDefault(compiler.Properties.Deny_warnings, config.DefaultDenyWarnings) 33} 34 35func (compiler *baseCompiler) setNoStdlibs() { 36 compiler.Properties.No_stdlibs = proptools.BoolPtr(true) 37} 38 39func NewBaseCompiler(dir, dir64 string, location installLocation) *baseCompiler { 40 return &baseCompiler{ 41 Properties: BaseCompilerProperties{}, 42 dir: dir, 43 dir64: dir64, 44 location: location, 45 } 46} 47 48type installLocation int 49 50const ( 51 InstallInSystem installLocation = 0 52 InstallInData = iota 53) 54 55type BaseCompilerProperties struct { 56 // whether to pass "-D warnings" to rustc. Defaults to true. 57 Deny_warnings *bool 58 59 // flags to pass to rustc 60 Flags []string `android:"path,arch_variant"` 61 62 // flags to pass to the linker 63 Ld_flags []string `android:"path,arch_variant"` 64 65 // list of rust rlib crate dependencies 66 Rlibs []string `android:"arch_variant"` 67 68 // list of rust dylib crate dependencies 69 Dylibs []string `android:"arch_variant"` 70 71 // list of rust proc_macro crate dependencies 72 Proc_macros []string `android:"arch_variant"` 73 74 // list of C shared library dependencies 75 Shared_libs []string `android:"arch_variant"` 76 77 // list of C static library dependencies 78 Static_libs []string `android:"arch_variant"` 79 80 // crate name, required for libraries. This must be the expected extern crate name used in source 81 Crate_name string `android:"arch_variant"` 82 83 // list of features to enable for this crate 84 Features []string `android:"arch_variant"` 85 86 // specific rust edition that should be used if the default version is not desired 87 Edition *string `android:"arch_variant"` 88 89 // sets name of the output 90 Stem *string `android:"arch_variant"` 91 92 // append to name of output 93 Suffix *string `android:"arch_variant"` 94 95 // install to a subdirectory of the default install path for the module 96 Relative_install_path *string `android:"arch_variant"` 97 98 // whether to suppress inclusion of standard crates - defaults to false 99 No_stdlibs *bool 100} 101 102type baseCompiler struct { 103 Properties BaseCompilerProperties 104 pathDeps android.Paths 105 rustFlagsDeps android.Paths 106 linkFlagsDeps android.Paths 107 flags string 108 linkFlags string 109 depFlags []string 110 linkDirs []string 111 edition string 112 src android.Path //rustc takes a single src file 113 114 // Install related 115 dir string 116 dir64 string 117 subDir string 118 relative string 119 path android.InstallPath 120 location installLocation 121} 122 123var _ compiler = (*baseCompiler)(nil) 124 125func (compiler *baseCompiler) inData() bool { 126 return compiler.location == InstallInData 127} 128 129func (compiler *baseCompiler) compilerProps() []interface{} { 130 return []interface{}{&compiler.Properties} 131} 132 133func (compiler *baseCompiler) featuresToFlags(features []string) []string { 134 flags := []string{} 135 for _, feature := range features { 136 flags = append(flags, "--cfg 'feature=\""+feature+"\"'") 137 } 138 return flags 139} 140 141func (compiler *baseCompiler) compilerFlags(ctx ModuleContext, flags Flags) Flags { 142 143 if getDenyWarnings(compiler) { 144 flags.RustFlags = append(flags.RustFlags, "-D warnings") 145 } 146 flags.RustFlags = append(flags.RustFlags, compiler.Properties.Flags...) 147 flags.RustFlags = append(flags.RustFlags, compiler.featuresToFlags(compiler.Properties.Features)...) 148 flags.RustFlags = append(flags.RustFlags, "--edition="+getEdition(compiler)) 149 flags.LinkFlags = append(flags.LinkFlags, compiler.Properties.Ld_flags...) 150 flags.GlobalRustFlags = append(flags.GlobalRustFlags, config.GlobalRustFlags...) 151 flags.GlobalRustFlags = append(flags.GlobalRustFlags, ctx.toolchain().ToolchainRustFlags()) 152 flags.GlobalLinkFlags = append(flags.GlobalLinkFlags, ctx.toolchain().ToolchainLinkFlags()) 153 154 if ctx.Host() && !ctx.Windows() { 155 rpath_prefix := `\$$ORIGIN/` 156 if ctx.Darwin() { 157 rpath_prefix = "@loader_path/" 158 } 159 160 var rpath string 161 if ctx.toolchain().Is64Bit() { 162 rpath = "lib64" 163 } else { 164 rpath = "lib" 165 } 166 flags.LinkFlags = append(flags.LinkFlags, "-Wl,-rpath,"+rpath_prefix+rpath) 167 flags.LinkFlags = append(flags.LinkFlags, "-Wl,-rpath,"+rpath_prefix+"../"+rpath) 168 } 169 170 return flags 171} 172 173func (compiler *baseCompiler) compile(ctx ModuleContext, flags Flags, deps PathDeps) android.Path { 174 panic(fmt.Errorf("baseCrater doesn't know how to crate things!")) 175} 176 177func (compiler *baseCompiler) compilerDeps(ctx DepsContext, deps Deps) Deps { 178 deps.Rlibs = append(deps.Rlibs, compiler.Properties.Rlibs...) 179 deps.Dylibs = append(deps.Dylibs, compiler.Properties.Dylibs...) 180 deps.ProcMacros = append(deps.ProcMacros, compiler.Properties.Proc_macros...) 181 deps.StaticLibs = append(deps.StaticLibs, compiler.Properties.Static_libs...) 182 deps.SharedLibs = append(deps.SharedLibs, compiler.Properties.Shared_libs...) 183 184 if !Bool(compiler.Properties.No_stdlibs) { 185 for _, stdlib := range config.Stdlibs { 186 // If we're building for host, use the compiler's stdlibs 187 if ctx.Host() { 188 stdlib = stdlib + "_" + ctx.toolchain().RustTriple() 189 } 190 191 // This check is technically insufficient - on the host, where 192 // static linking is the default, if one of our static 193 // dependencies uses a dynamic library, we need to dynamically 194 // link the stdlib as well. 195 if (len(deps.Dylibs) > 0) || (!ctx.Host()) { 196 // Dynamically linked stdlib 197 deps.Dylibs = append(deps.Dylibs, stdlib) 198 } 199 } 200 } 201 return deps 202} 203 204func (compiler *baseCompiler) bionicDeps(ctx DepsContext, deps Deps) Deps { 205 deps.SharedLibs = append(deps.SharedLibs, "liblog") 206 deps.SharedLibs = append(deps.SharedLibs, "libc") 207 deps.SharedLibs = append(deps.SharedLibs, "libm") 208 deps.SharedLibs = append(deps.SharedLibs, "libdl") 209 210 //TODO(b/141331117) libstd requires libgcc on Android 211 deps.StaticLibs = append(deps.StaticLibs, "libgcc") 212 213 return deps 214} 215 216func (compiler *baseCompiler) crateName() string { 217 return compiler.Properties.Crate_name 218} 219 220func (compiler *baseCompiler) installDir(ctx ModuleContext) android.InstallPath { 221 dir := compiler.dir 222 if ctx.toolchain().Is64Bit() && compiler.dir64 != "" { 223 dir = compiler.dir64 224 } 225 if !ctx.Host() || ctx.Target().NativeBridge == android.NativeBridgeEnabled { 226 dir = filepath.Join(dir, ctx.Arch().ArchType.String()) 227 } 228 return android.PathForModuleInstall(ctx, dir, compiler.subDir, 229 compiler.relativeInstallPath(), compiler.relative) 230} 231 232func (compiler *baseCompiler) install(ctx ModuleContext, file android.Path) { 233 compiler.path = ctx.InstallFile(compiler.installDir(ctx), file.Base(), file) 234} 235 236func (compiler *baseCompiler) getStem(ctx ModuleContext) string { 237 return compiler.getStemWithoutSuffix(ctx) + String(compiler.Properties.Suffix) 238} 239 240func (compiler *baseCompiler) getStemWithoutSuffix(ctx BaseModuleContext) string { 241 stem := ctx.baseModuleName() 242 if String(compiler.Properties.Stem) != "" { 243 stem = String(compiler.Properties.Stem) 244 } 245 246 return stem 247} 248 249func (compiler *baseCompiler) relativeInstallPath() string { 250 return String(compiler.Properties.Relative_install_path) 251} 252 253func srcPathFromModuleSrcs(ctx ModuleContext, srcs []string) android.Path { 254 srcPaths := android.PathsForModuleSrc(ctx, srcs) 255 if len(srcPaths) != 1 { 256 ctx.PropertyErrorf("srcs", "srcs can only contain one path for rust modules") 257 } 258 return srcPaths[0] 259} 260