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 "android/soong/cc" 19 "fmt" 20 "path/filepath" 21 "strings" 22 23 "github.com/google/blueprint/proptools" 24 25 "android/soong/android" 26 "android/soong/rust/config" 27) 28 29type RustLinkage int 30 31const ( 32 DefaultLinkage RustLinkage = iota 33 RlibLinkage 34 DylibLinkage 35) 36 37func (compiler *baseCompiler) edition() string { 38 return proptools.StringDefault(compiler.Properties.Edition, config.DefaultEdition) 39} 40 41func (compiler *baseCompiler) setNoStdlibs() { 42 compiler.Properties.No_stdlibs = proptools.BoolPtr(true) 43} 44 45func (compiler *baseCompiler) disableLints() { 46 compiler.Properties.Lints = proptools.StringPtr("none") 47} 48 49func NewBaseCompiler(dir, dir64 string, location installLocation) *baseCompiler { 50 return &baseCompiler{ 51 Properties: BaseCompilerProperties{}, 52 dir: dir, 53 dir64: dir64, 54 location: location, 55 } 56} 57 58type installLocation int 59 60const ( 61 InstallInSystem installLocation = 0 62 InstallInData = iota 63 64 incorrectSourcesError = "srcs can only contain one path for a rust file and source providers prefixed by \":\"" 65 genSubDir = "out/" 66) 67 68type BaseCompilerProperties struct { 69 // path to the source file that is the main entry point of the program (e.g. main.rs or lib.rs). 70 // Only a single source file can be defined. Modules which generate source can be included by prefixing 71 // the module name with ":", for example ":libfoo_bindgen" 72 // 73 // If no source file is defined, a single generated source module can be defined to be used as the main source. 74 Srcs []string `android:"path,arch_variant"` 75 76 // name of the lint set that should be used to validate this module. 77 // 78 // Possible values are "default" (for using a sensible set of lints 79 // depending on the module's location), "android" (for the strictest 80 // lint set that applies to all Android platform code), "vendor" (for 81 // a relaxed set) and "none" (for ignoring all lint warnings and 82 // errors). The default value is "default". 83 Lints *string 84 85 // flags to pass to rustc. To enable configuration options or features, use the "cfgs" or "features" properties. 86 Flags []string `android:"arch_variant"` 87 88 // flags to pass to the linker 89 Ld_flags []string `android:"arch_variant"` 90 91 // list of rust rlib crate dependencies 92 Rlibs []string `android:"arch_variant"` 93 94 // list of rust dylib crate dependencies 95 Dylibs []string `android:"arch_variant"` 96 97 // list of rust automatic crate dependencies 98 Rustlibs []string `android:"arch_variant"` 99 100 // list of rust proc_macro crate dependencies 101 Proc_macros []string `android:"arch_variant"` 102 103 // list of C shared library dependencies 104 Shared_libs []string `android:"arch_variant"` 105 106 // list of C static library dependencies. These dependencies do not normally propagate to dependents 107 // and may need to be redeclared. See whole_static_libs for bundling static dependencies into a library. 108 Static_libs []string `android:"arch_variant"` 109 110 // Similar to static_libs, but will bundle the static library dependency into a library. This is helpful 111 // to avoid having to redeclare the dependency for dependents of this library, but in some cases may also 112 // result in bloat if multiple dependencies all include the same static library whole. 113 // 114 // The common use case for this is when the static library is unlikely to be a dependency of other modules to avoid 115 // having to redeclare the static library dependency for every dependent module. 116 // If you are not sure what to, for rust_library modules most static dependencies should go in static_libraries, 117 // and for rust_ffi modules most static dependencies should go into whole_static_libraries. 118 // 119 // For rust_ffi static variants, these libraries will be included in the resulting static library archive. 120 // 121 // For rust_library rlib variants, these libraries will be bundled into the resulting rlib library. This will 122 // include all of the static libraries symbols in any dylibs or binaries which use this rlib as well. 123 Whole_static_libs []string `android:"arch_variant"` 124 125 // list of Rust system library dependencies. 126 // 127 // This is usually only needed when `no_stdlibs` is true, in which case it can be used to depend on system crates 128 // like `core` and `alloc`. 129 Stdlibs []string `android:"arch_variant"` 130 131 // crate name, required for modules which produce Rust libraries: rust_library, rust_ffi and SourceProvider 132 // modules which create library variants (rust_bindgen). This must be the expected extern crate name used in 133 // source, and is required to conform to an enforced format matching library output files (if the output file is 134 // lib<someName><suffix>, the crate_name property must be <someName>). 135 Crate_name string `android:"arch_variant"` 136 137 // list of features to enable for this crate 138 Features []string `android:"arch_variant"` 139 140 // list of configuration options to enable for this crate. To enable features, use the "features" property. 141 Cfgs []string `android:"arch_variant"` 142 143 // specific rust edition that should be used if the default version is not desired 144 Edition *string `android:"arch_variant"` 145 146 // sets name of the output 147 Stem *string `android:"arch_variant"` 148 149 // append to name of output 150 Suffix *string `android:"arch_variant"` 151 152 // install to a subdirectory of the default install path for the module 153 Relative_install_path *string `android:"arch_variant"` 154 155 // whether to suppress inclusion of standard crates - defaults to false 156 No_stdlibs *bool 157 158 // Change the rustlibs linkage to select rlib linkage by default for device targets. 159 // Also link libstd as an rlib as well on device targets. 160 // Note: This is the default behavior for host targets. 161 // 162 // This is primarily meant for rust_binary and rust_ffi modules where the default 163 // linkage of libstd might need to be overridden in some use cases. This should 164 // generally be avoided with other module types since it may cause collisions at 165 // linkage if all dependencies of the root binary module do not link against libstd 166 // the same way. 167 Prefer_rlib *bool `android:"arch_variant"` 168 169 // Enables emitting certain Cargo environment variables. Only intended to be used for compatibility purposes. 170 // Will set CARGO_CRATE_NAME to the crate_name property's value. 171 // Will set CARGO_BIN_NAME to the output filename value without the extension. 172 Cargo_env_compat *bool 173 174 // If cargo_env_compat is true, sets the CARGO_PKG_VERSION env var to this value. 175 Cargo_pkg_version *string 176} 177 178type baseCompiler struct { 179 Properties BaseCompilerProperties 180 181 // Install related 182 dir string 183 dir64 string 184 subDir string 185 relative string 186 path android.InstallPath 187 location installLocation 188 sanitize *sanitize 189 190 distFile android.OptionalPath 191 192 // unstripped output file. 193 unstrippedOutputFile android.Path 194 195 // stripped output file. 196 strippedOutputFile android.OptionalPath 197 198 // If a crate has a source-generated dependency, a copy of the source file 199 // will be available in cargoOutDir (equivalent to Cargo OUT_DIR). 200 cargoOutDir android.ModuleOutPath 201} 202 203func (compiler *baseCompiler) Disabled() bool { 204 return false 205} 206 207func (compiler *baseCompiler) SetDisabled() { 208 panic("baseCompiler does not implement SetDisabled()") 209} 210 211func (compiler *baseCompiler) noStdlibs() bool { 212 return Bool(compiler.Properties.No_stdlibs) 213} 214 215func (compiler *baseCompiler) coverageOutputZipPath() android.OptionalPath { 216 panic("baseCompiler does not implement coverageOutputZipPath()") 217} 218 219func (compiler *baseCompiler) preferRlib() bool { 220 return Bool(compiler.Properties.Prefer_rlib) 221} 222 223func (compiler *baseCompiler) stdLinkage(ctx *depsContext) RustLinkage { 224 // For devices, we always link stdlibs in as dylibs by default. 225 if compiler.preferRlib() { 226 return RlibLinkage 227 } else if ctx.Device() { 228 return DylibLinkage 229 } else { 230 return RlibLinkage 231 } 232} 233 234var _ compiler = (*baseCompiler)(nil) 235 236func (compiler *baseCompiler) inData() bool { 237 return compiler.location == InstallInData 238} 239 240func (compiler *baseCompiler) compilerProps() []interface{} { 241 return []interface{}{&compiler.Properties} 242} 243 244func (compiler *baseCompiler) cfgsToFlags() []string { 245 flags := []string{} 246 for _, cfg := range compiler.Properties.Cfgs { 247 flags = append(flags, "--cfg '"+cfg+"'") 248 } 249 250 return flags 251} 252 253func (compiler *baseCompiler) featuresToFlags() []string { 254 flags := []string{} 255 for _, feature := range compiler.Properties.Features { 256 flags = append(flags, "--cfg 'feature=\""+feature+"\"'") 257 } 258 259 return flags 260} 261 262func (compiler *baseCompiler) featureFlags(ctx ModuleContext, flags Flags) Flags { 263 flags.RustFlags = append(flags.RustFlags, compiler.featuresToFlags()...) 264 flags.RustdocFlags = append(flags.RustdocFlags, compiler.featuresToFlags()...) 265 266 return flags 267} 268 269func (compiler *baseCompiler) cfgFlags(ctx ModuleContext, flags Flags) Flags { 270 if ctx.RustModule().UseVndk() { 271 compiler.Properties.Cfgs = append(compiler.Properties.Cfgs, "android_vndk") 272 if ctx.RustModule().InVendor() { 273 compiler.Properties.Cfgs = append(compiler.Properties.Cfgs, "android_vendor") 274 } else if ctx.RustModule().InProduct() { 275 compiler.Properties.Cfgs = append(compiler.Properties.Cfgs, "android_product") 276 } 277 } 278 279 flags.RustFlags = append(flags.RustFlags, compiler.cfgsToFlags()...) 280 flags.RustdocFlags = append(flags.RustdocFlags, compiler.cfgsToFlags()...) 281 return flags 282} 283 284func (compiler *baseCompiler) compilerFlags(ctx ModuleContext, flags Flags) Flags { 285 286 lintFlags, err := config.RustcLintsForDir(ctx.ModuleDir(), compiler.Properties.Lints) 287 if err != nil { 288 ctx.PropertyErrorf("lints", err.Error()) 289 } 290 291 // linkage-related flags are disallowed. 292 for _, s := range compiler.Properties.Ld_flags { 293 if strings.HasPrefix(s, "-Wl,-l") || strings.HasPrefix(s, "-Wl,-L") { 294 ctx.PropertyErrorf("ld_flags", "'-Wl,-l' and '-Wl,-L' flags cannot be manually specified") 295 } 296 } 297 for _, s := range compiler.Properties.Flags { 298 if strings.HasPrefix(s, "-l") || strings.HasPrefix(s, "-L") { 299 ctx.PropertyErrorf("flags", "'-l' and '-L' flags cannot be manually specified") 300 } 301 if strings.HasPrefix(s, "--extern") { 302 ctx.PropertyErrorf("flags", "'--extern' flag cannot be manually specified") 303 } 304 if strings.HasPrefix(s, "-Clink-args=") || strings.HasPrefix(s, "-C link-args=") { 305 ctx.PropertyErrorf("flags", "'-C link-args' flag cannot be manually specified") 306 } 307 } 308 309 flags.RustFlags = append(flags.RustFlags, lintFlags) 310 flags.RustFlags = append(flags.RustFlags, compiler.Properties.Flags...) 311 flags.RustFlags = append(flags.RustFlags, "--edition="+compiler.edition()) 312 flags.RustdocFlags = append(flags.RustdocFlags, "--edition="+compiler.edition()) 313 flags.LinkFlags = append(flags.LinkFlags, compiler.Properties.Ld_flags...) 314 flags.GlobalRustFlags = append(flags.GlobalRustFlags, config.GlobalRustFlags...) 315 flags.GlobalRustFlags = append(flags.GlobalRustFlags, ctx.toolchain().ToolchainRustFlags()) 316 flags.GlobalLinkFlags = append(flags.GlobalLinkFlags, ctx.toolchain().ToolchainLinkFlags()) 317 flags.EmitXrefs = ctx.Config().EmitXrefRules() 318 319 if ctx.Host() && !ctx.Windows() { 320 flags.LinkFlags = append(flags.LinkFlags, cc.RpathFlags(ctx)...) 321 } 322 323 return flags 324} 325 326func (compiler *baseCompiler) compile(ctx ModuleContext, flags Flags, deps PathDeps) buildOutput { 327 panic(fmt.Errorf("baseCrater doesn't know how to crate things!")) 328} 329 330func (compiler *baseCompiler) rustdoc(ctx ModuleContext, flags Flags, 331 deps PathDeps) android.OptionalPath { 332 333 return android.OptionalPath{} 334} 335 336func (compiler *baseCompiler) initialize(ctx ModuleContext) { 337 compiler.cargoOutDir = android.PathForModuleOut(ctx, genSubDir) 338} 339 340func (compiler *baseCompiler) CargoOutDir() android.OptionalPath { 341 return android.OptionalPathForPath(compiler.cargoOutDir) 342} 343 344func (compiler *baseCompiler) CargoEnvCompat() bool { 345 return Bool(compiler.Properties.Cargo_env_compat) 346} 347 348func (compiler *baseCompiler) CargoPkgVersion() string { 349 return String(compiler.Properties.Cargo_pkg_version) 350} 351 352func (compiler *baseCompiler) unstrippedOutputFilePath() android.Path { 353 return compiler.unstrippedOutputFile 354} 355 356func (compiler *baseCompiler) strippedOutputFilePath() android.OptionalPath { 357 return compiler.strippedOutputFile 358} 359 360func (compiler *baseCompiler) compilerDeps(ctx DepsContext, deps Deps) Deps { 361 deps.Rlibs = append(deps.Rlibs, compiler.Properties.Rlibs...) 362 deps.Dylibs = append(deps.Dylibs, compiler.Properties.Dylibs...) 363 deps.Rustlibs = append(deps.Rustlibs, compiler.Properties.Rustlibs...) 364 deps.ProcMacros = append(deps.ProcMacros, compiler.Properties.Proc_macros...) 365 deps.StaticLibs = append(deps.StaticLibs, compiler.Properties.Static_libs...) 366 deps.WholeStaticLibs = append(deps.WholeStaticLibs, compiler.Properties.Whole_static_libs...) 367 deps.SharedLibs = append(deps.SharedLibs, compiler.Properties.Shared_libs...) 368 deps.Stdlibs = append(deps.Stdlibs, compiler.Properties.Stdlibs...) 369 370 if !Bool(compiler.Properties.No_stdlibs) { 371 for _, stdlib := range config.Stdlibs { 372 // If we're building for the build host, use the prebuilt stdlibs, unless the host 373 // is linux_bionic which doesn't have prebuilts. 374 if ctx.Host() && !ctx.Target().HostCross && ctx.Target().Os != android.LinuxBionic { 375 stdlib = "prebuilt_" + stdlib 376 } 377 deps.Stdlibs = append(deps.Stdlibs, stdlib) 378 } 379 } 380 return deps 381} 382 383func bionicDeps(ctx DepsContext, deps Deps, static bool) Deps { 384 bionicLibs := []string{} 385 bionicLibs = append(bionicLibs, "liblog") 386 bionicLibs = append(bionicLibs, "libc") 387 bionicLibs = append(bionicLibs, "libm") 388 bionicLibs = append(bionicLibs, "libdl") 389 390 if static { 391 deps.StaticLibs = append(deps.StaticLibs, bionicLibs...) 392 } else { 393 deps.SharedLibs = append(deps.SharedLibs, bionicLibs...) 394 } 395 if ctx.RustModule().StaticExecutable() { 396 deps.StaticLibs = append(deps.StaticLibs, "libunwind") 397 } 398 if libRuntimeBuiltins := config.BuiltinsRuntimeLibrary(ctx.toolchain()); libRuntimeBuiltins != "" { 399 deps.StaticLibs = append(deps.StaticLibs, libRuntimeBuiltins) 400 } 401 return deps 402} 403 404func muslDeps(ctx DepsContext, deps Deps, static bool) Deps { 405 muslLibs := []string{"libc_musl"} 406 if static { 407 deps.StaticLibs = append(deps.StaticLibs, muslLibs...) 408 } else { 409 deps.SharedLibs = append(deps.SharedLibs, muslLibs...) 410 } 411 if libRuntimeBuiltins := config.BuiltinsRuntimeLibrary(ctx.toolchain()); libRuntimeBuiltins != "" { 412 deps.StaticLibs = append(deps.StaticLibs, libRuntimeBuiltins) 413 } 414 415 return deps 416} 417 418func (compiler *baseCompiler) crateName() string { 419 return compiler.Properties.Crate_name 420} 421 422func (compiler *baseCompiler) everInstallable() bool { 423 // Most modules are installable, so return true by default. 424 return true 425} 426 427func (compiler *baseCompiler) installDir(ctx ModuleContext) android.InstallPath { 428 dir := compiler.dir 429 if ctx.toolchain().Is64Bit() && compiler.dir64 != "" { 430 dir = compiler.dir64 431 } 432 if ctx.Target().NativeBridge == android.NativeBridgeEnabled { 433 dir = filepath.Join(dir, ctx.Target().NativeBridgeRelativePath) 434 } 435 if !ctx.Host() && ctx.Config().HasMultilibConflict(ctx.Arch().ArchType) { 436 dir = filepath.Join(dir, ctx.Arch().ArchType.String()) 437 } 438 439 if compiler.location == InstallInData && ctx.RustModule().UseVndk() { 440 if ctx.RustModule().InProduct() { 441 dir = filepath.Join(dir, "product") 442 } else if ctx.RustModule().InVendor() { 443 dir = filepath.Join(dir, "vendor") 444 } else { 445 ctx.ModuleErrorf("Unknown data+VNDK installation kind") 446 } 447 } 448 449 return android.PathForModuleInstall(ctx, dir, compiler.subDir, 450 compiler.relativeInstallPath(), compiler.relative) 451} 452 453func (compiler *baseCompiler) nativeCoverage() bool { 454 return false 455} 456 457func (compiler *baseCompiler) install(ctx ModuleContext) { 458 path := ctx.RustModule().OutputFile() 459 compiler.path = ctx.InstallFile(compiler.installDir(ctx), path.Path().Base(), path.Path()) 460} 461 462func (compiler *baseCompiler) getStem(ctx ModuleContext) string { 463 return compiler.getStemWithoutSuffix(ctx) + String(compiler.Properties.Suffix) 464} 465 466func (compiler *baseCompiler) getStemWithoutSuffix(ctx BaseModuleContext) string { 467 stem := ctx.ModuleName() 468 if String(compiler.Properties.Stem) != "" { 469 stem = String(compiler.Properties.Stem) 470 } 471 472 return stem 473} 474 475func (compiler *baseCompiler) relativeInstallPath() string { 476 return String(compiler.Properties.Relative_install_path) 477} 478 479// Returns the Path for the main source file along with Paths for generated source files from modules listed in srcs. 480func srcPathFromModuleSrcs(ctx ModuleContext, srcs []string) (android.Path, android.Paths) { 481 if len(srcs) == 0 { 482 ctx.PropertyErrorf("srcs", "srcs must not be empty") 483 } 484 485 // The srcs can contain strings with prefix ":". 486 // They are dependent modules of this module, with android.SourceDepTag. 487 // They are not the main source file compiled by rustc. 488 numSrcs := 0 489 srcIndex := 0 490 for i, s := range srcs { 491 if android.SrcIsModule(s) == "" { 492 numSrcs++ 493 srcIndex = i 494 } 495 } 496 if numSrcs > 1 { 497 ctx.PropertyErrorf("srcs", incorrectSourcesError) 498 } 499 500 // If a main source file is not provided we expect only a single SourceProvider module to be defined 501 // within srcs, with the expectation that the first source it provides is the entry point. 502 if srcIndex != 0 { 503 ctx.PropertyErrorf("srcs", "main source file must be the first in srcs") 504 } else if numSrcs > 1 { 505 ctx.PropertyErrorf("srcs", "only a single generated source module can be defined without a main source file.") 506 } 507 508 paths := android.PathsForModuleSrc(ctx, srcs) 509 return paths[srcIndex], paths[1:] 510} 511