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 27type RustLinkage int 28 29const ( 30 DefaultLinkage RustLinkage = iota 31 RlibLinkage 32 DylibLinkage 33) 34 35func (compiler *baseCompiler) edition() string { 36 return proptools.StringDefault(compiler.Properties.Edition, config.DefaultEdition) 37} 38 39func (compiler *baseCompiler) setNoStdlibs() { 40 compiler.Properties.No_stdlibs = proptools.BoolPtr(true) 41} 42 43func (compiler *baseCompiler) disableLints() { 44 compiler.Properties.Lints = proptools.StringPtr("none") 45} 46 47func NewBaseCompiler(dir, dir64 string, location installLocation) *baseCompiler { 48 return &baseCompiler{ 49 Properties: BaseCompilerProperties{}, 50 dir: dir, 51 dir64: dir64, 52 location: location, 53 } 54} 55 56type installLocation int 57 58const ( 59 InstallInSystem installLocation = 0 60 InstallInData = iota 61 62 incorrectSourcesError = "srcs can only contain one path for a rust file and source providers prefixed by \":\"" 63 genSubDir = "out/" 64) 65 66type BaseCompilerProperties struct { 67 // path to the source file that is the main entry point of the program (e.g. main.rs or lib.rs) 68 Srcs []string `android:"path,arch_variant"` 69 70 // name of the lint set that should be used to validate this module. 71 // 72 // Possible values are "default" (for using a sensible set of lints 73 // depending on the module's location), "android" (for the strictest 74 // lint set that applies to all Android platform code), "vendor" (for 75 // a relaxed set) and "none" (for ignoring all lint warnings and 76 // errors). The default value is "default". 77 Lints *string 78 79 // flags to pass to rustc. To enable configuration options or features, use the "cfgs" or "features" properties. 80 Flags []string `android:"arch_variant"` 81 82 // flags to pass to the linker 83 Ld_flags []string `android:"arch_variant"` 84 85 // list of rust rlib crate dependencies 86 Rlibs []string `android:"arch_variant"` 87 88 // list of rust dylib crate dependencies 89 Dylibs []string `android:"arch_variant"` 90 91 // list of rust automatic crate dependencies 92 Rustlibs []string `android:"arch_variant"` 93 94 // list of rust proc_macro crate dependencies 95 Proc_macros []string `android:"arch_variant"` 96 97 // list of C shared library dependencies 98 Shared_libs []string `android:"arch_variant"` 99 100 // list of C static library dependencies. These dependencies do not normally propagate to dependents 101 // and may need to be redeclared. See whole_static_libs for bundling static dependencies into a library. 102 Static_libs []string `android:"arch_variant"` 103 104 // Similar to static_libs, but will bundle the static library dependency into a library. This is helpful 105 // to avoid having to redeclare the dependency for dependents of this library, but in some cases may also 106 // result in bloat if multiple dependencies all include the same static library whole. 107 // 108 // The common use case for this is when the static library is unlikely to be a dependency of other modules to avoid 109 // having to redeclare the static library dependency for every dependent module. 110 // If you are not sure what to, for rust_library modules most static dependencies should go in static_libraries, 111 // and for rust_ffi modules most static dependencies should go into whole_static_libraries. 112 // 113 // For rust_ffi static variants, these libraries will be included in the resulting static library archive. 114 // 115 // For rust_library rlib variants, these libraries will be bundled into the resulting rlib library. This will 116 // include all of the static libraries symbols in any dylibs or binaries which use this rlib as well. 117 Whole_static_libs []string `android:"arch_variant"` 118 119 // crate name, required for modules which produce Rust libraries: rust_library, rust_ffi and SourceProvider 120 // modules which create library variants (rust_bindgen). This must be the expected extern crate name used in 121 // source, and is required to conform to an enforced format matching library output files (if the output file is 122 // lib<someName><suffix>, the crate_name property must be <someName>). 123 Crate_name string `android:"arch_variant"` 124 125 // list of features to enable for this crate 126 Features []string `android:"arch_variant"` 127 128 // list of configuration options to enable for this crate. To enable features, use the "features" property. 129 Cfgs []string `android:"arch_variant"` 130 131 // specific rust edition that should be used if the default version is not desired 132 Edition *string `android:"arch_variant"` 133 134 // sets name of the output 135 Stem *string `android:"arch_variant"` 136 137 // append to name of output 138 Suffix *string `android:"arch_variant"` 139 140 // install to a subdirectory of the default install path for the module 141 Relative_install_path *string `android:"arch_variant"` 142 143 // whether to suppress inclusion of standard crates - defaults to false 144 No_stdlibs *bool 145 146 // Change the rustlibs linkage to select rlib linkage by default for device targets. 147 // Also link libstd as an rlib as well on device targets. 148 // Note: This is the default behavior for host targets. 149 // 150 // This is primarily meant for rust_binary and rust_ffi modules where the default 151 // linkage of libstd might need to be overridden in some use cases. This should 152 // generally be avoided with other module types since it may cause collisions at 153 // linkage if all dependencies of the root binary module do not link against libstd\ 154 // the same way. 155 Prefer_rlib *bool `android:"arch_variant"` 156} 157 158type baseCompiler struct { 159 Properties BaseCompilerProperties 160 161 // Install related 162 dir string 163 dir64 string 164 subDir string 165 relative string 166 path android.InstallPath 167 location installLocation 168 sanitize *sanitize 169 170 distFile android.OptionalPath 171 // Stripped output file. If Valid(), this file will be installed instead of outputFile. 172 strippedOutputFile android.OptionalPath 173 174 // If a crate has a source-generated dependency, a copy of the source file 175 // will be available in cargoOutDir (equivalent to Cargo OUT_DIR). 176 cargoOutDir android.ModuleOutPath 177} 178 179func (compiler *baseCompiler) Disabled() bool { 180 return false 181} 182 183func (compiler *baseCompiler) SetDisabled() { 184 panic("baseCompiler does not implement SetDisabled()") 185} 186 187func (compiler *baseCompiler) coverageOutputZipPath() android.OptionalPath { 188 panic("baseCompiler does not implement coverageOutputZipPath()") 189} 190 191func (compiler *baseCompiler) preferRlib() bool { 192 return Bool(compiler.Properties.Prefer_rlib) 193} 194 195func (compiler *baseCompiler) stdLinkage(ctx *depsContext) RustLinkage { 196 // For devices, we always link stdlibs in as dylibs by default. 197 if compiler.preferRlib() { 198 return RlibLinkage 199 } else if ctx.Device() { 200 return DylibLinkage 201 } else { 202 return RlibLinkage 203 } 204} 205 206var _ compiler = (*baseCompiler)(nil) 207 208func (compiler *baseCompiler) inData() bool { 209 return compiler.location == InstallInData 210} 211 212func (compiler *baseCompiler) compilerProps() []interface{} { 213 return []interface{}{&compiler.Properties} 214} 215 216func (compiler *baseCompiler) cfgsToFlags() []string { 217 flags := []string{} 218 for _, cfg := range compiler.Properties.Cfgs { 219 flags = append(flags, "--cfg '"+cfg+"'") 220 } 221 return flags 222} 223 224func (compiler *baseCompiler) featuresToFlags() []string { 225 flags := []string{} 226 for _, feature := range compiler.Properties.Features { 227 flags = append(flags, "--cfg 'feature=\""+feature+"\"'") 228 } 229 return flags 230} 231 232func (compiler *baseCompiler) compilerFlags(ctx ModuleContext, flags Flags) Flags { 233 234 lintFlags, err := config.RustcLintsForDir(ctx.ModuleDir(), compiler.Properties.Lints) 235 if err != nil { 236 ctx.PropertyErrorf("lints", err.Error()) 237 } 238 flags.RustFlags = append(flags.RustFlags, lintFlags) 239 flags.RustFlags = append(flags.RustFlags, compiler.Properties.Flags...) 240 flags.RustFlags = append(flags.RustFlags, compiler.cfgsToFlags()...) 241 flags.RustFlags = append(flags.RustFlags, compiler.featuresToFlags()...) 242 flags.RustdocFlags = append(flags.RustdocFlags, compiler.cfgsToFlags()...) 243 flags.RustdocFlags = append(flags.RustdocFlags, compiler.featuresToFlags()...) 244 flags.RustFlags = append(flags.RustFlags, "--edition="+compiler.edition()) 245 flags.RustdocFlags = append(flags.RustdocFlags, "--edition="+compiler.edition()) 246 flags.LinkFlags = append(flags.LinkFlags, compiler.Properties.Ld_flags...) 247 flags.GlobalRustFlags = append(flags.GlobalRustFlags, config.GlobalRustFlags...) 248 flags.GlobalRustFlags = append(flags.GlobalRustFlags, ctx.toolchain().ToolchainRustFlags()) 249 flags.GlobalLinkFlags = append(flags.GlobalLinkFlags, ctx.toolchain().ToolchainLinkFlags()) 250 251 if ctx.Host() && !ctx.Windows() { 252 rpathPrefix := `\$$ORIGIN/` 253 if ctx.Darwin() { 254 rpathPrefix = "@loader_path/" 255 } 256 257 var rpath string 258 if ctx.toolchain().Is64Bit() { 259 rpath = "lib64" 260 } else { 261 rpath = "lib" 262 } 263 flags.LinkFlags = append(flags.LinkFlags, "-Wl,-rpath,"+rpathPrefix+rpath) 264 flags.LinkFlags = append(flags.LinkFlags, "-Wl,-rpath,"+rpathPrefix+"../"+rpath) 265 } 266 267 if ctx.RustModule().UseVndk() { 268 flags.RustFlags = append(flags.RustFlags, "--cfg 'android_vndk'") 269 } 270 271 return flags 272} 273 274func (compiler *baseCompiler) compile(ctx ModuleContext, flags Flags, deps PathDeps) android.Path { 275 panic(fmt.Errorf("baseCrater doesn't know how to crate things!")) 276} 277 278func (compiler *baseCompiler) rustdoc(ctx ModuleContext, flags Flags, 279 deps PathDeps) android.OptionalPath { 280 281 return android.OptionalPath{} 282} 283 284func (compiler *baseCompiler) initialize(ctx ModuleContext) { 285 compiler.cargoOutDir = android.PathForModuleOut(ctx, genSubDir) 286} 287 288func (compiler *baseCompiler) CargoOutDir() android.OptionalPath { 289 return android.OptionalPathForPath(compiler.cargoOutDir) 290} 291 292func (compiler *baseCompiler) isDependencyRoot() bool { 293 return false 294} 295 296func (compiler *baseCompiler) strippedOutputFilePath() android.OptionalPath { 297 return compiler.strippedOutputFile 298} 299 300func (compiler *baseCompiler) compilerDeps(ctx DepsContext, deps Deps) Deps { 301 deps.Rlibs = append(deps.Rlibs, compiler.Properties.Rlibs...) 302 deps.Dylibs = append(deps.Dylibs, compiler.Properties.Dylibs...) 303 deps.Rustlibs = append(deps.Rustlibs, compiler.Properties.Rustlibs...) 304 deps.ProcMacros = append(deps.ProcMacros, compiler.Properties.Proc_macros...) 305 deps.StaticLibs = append(deps.StaticLibs, compiler.Properties.Static_libs...) 306 deps.WholeStaticLibs = append(deps.WholeStaticLibs, compiler.Properties.Whole_static_libs...) 307 deps.SharedLibs = append(deps.SharedLibs, compiler.Properties.Shared_libs...) 308 309 if !Bool(compiler.Properties.No_stdlibs) { 310 for _, stdlib := range config.Stdlibs { 311 // If we're building for the primary arch of the build host, use the compiler's stdlibs 312 if ctx.Target().Os == android.BuildOs { 313 stdlib = stdlib + "_" + ctx.toolchain().RustTriple() 314 } 315 deps.Stdlibs = append(deps.Stdlibs, stdlib) 316 } 317 } 318 return deps 319} 320 321func bionicDeps(ctx DepsContext, deps Deps, static bool) Deps { 322 bionicLibs := []string{} 323 bionicLibs = append(bionicLibs, "liblog") 324 bionicLibs = append(bionicLibs, "libc") 325 bionicLibs = append(bionicLibs, "libm") 326 bionicLibs = append(bionicLibs, "libdl") 327 328 if static { 329 deps.StaticLibs = append(deps.StaticLibs, bionicLibs...) 330 } else { 331 deps.SharedLibs = append(deps.SharedLibs, bionicLibs...) 332 } 333 334 if libRuntimeBuiltins := config.BuiltinsRuntimeLibrary(ctx.toolchain()); libRuntimeBuiltins != "" { 335 deps.StaticLibs = append(deps.StaticLibs, libRuntimeBuiltins) 336 } 337 return deps 338} 339 340func (compiler *baseCompiler) crateName() string { 341 return compiler.Properties.Crate_name 342} 343 344func (compiler *baseCompiler) everInstallable() bool { 345 // Most modules are installable, so return true by default. 346 return true 347} 348 349func (compiler *baseCompiler) installDir(ctx ModuleContext) android.InstallPath { 350 dir := compiler.dir 351 if ctx.toolchain().Is64Bit() && compiler.dir64 != "" { 352 dir = compiler.dir64 353 } 354 if ctx.Target().NativeBridge == android.NativeBridgeEnabled { 355 dir = filepath.Join(dir, ctx.Target().NativeBridgeRelativePath) 356 } 357 if !ctx.Host() && ctx.Config().HasMultilibConflict(ctx.Arch().ArchType) { 358 dir = filepath.Join(dir, ctx.Arch().ArchType.String()) 359 } 360 361 if compiler.location == InstallInData && ctx.RustModule().UseVndk() { 362 dir = filepath.Join(dir, "vendor") 363 } 364 return android.PathForModuleInstall(ctx, dir, compiler.subDir, 365 compiler.relativeInstallPath(), compiler.relative) 366} 367 368func (compiler *baseCompiler) nativeCoverage() bool { 369 return false 370} 371 372func (compiler *baseCompiler) install(ctx ModuleContext) { 373 path := ctx.RustModule().OutputFile() 374 compiler.path = ctx.InstallFile(compiler.installDir(ctx), path.Path().Base(), path.Path()) 375} 376 377func (compiler *baseCompiler) getStem(ctx ModuleContext) string { 378 return compiler.getStemWithoutSuffix(ctx) + String(compiler.Properties.Suffix) 379} 380 381func (compiler *baseCompiler) getStemWithoutSuffix(ctx BaseModuleContext) string { 382 stem := ctx.ModuleName() 383 if String(compiler.Properties.Stem) != "" { 384 stem = String(compiler.Properties.Stem) 385 } 386 387 return stem 388} 389 390func (compiler *baseCompiler) relativeInstallPath() string { 391 return String(compiler.Properties.Relative_install_path) 392} 393 394// Returns the Path for the main source file along with Paths for generated source files from modules listed in srcs. 395func srcPathFromModuleSrcs(ctx ModuleContext, srcs []string) (android.Path, android.Paths) { 396 // The srcs can contain strings with prefix ":". 397 // They are dependent modules of this module, with android.SourceDepTag. 398 // They are not the main source file compiled by rustc. 399 numSrcs := 0 400 srcIndex := 0 401 for i, s := range srcs { 402 if android.SrcIsModule(s) == "" { 403 numSrcs++ 404 srcIndex = i 405 } 406 } 407 if numSrcs != 1 { 408 ctx.PropertyErrorf("srcs", incorrectSourcesError) 409 } 410 if srcIndex != 0 { 411 ctx.PropertyErrorf("srcs", "main source file must be the first in srcs") 412 } 413 paths := android.PathsForModuleSrc(ctx, srcs) 414 return paths[srcIndex], paths[1:] 415} 416