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 "regexp" 19 "strings" 20 21 "android/soong/android" 22) 23 24func init() { 25 android.RegisterModuleType("rust_library", RustLibraryFactory) 26 android.RegisterModuleType("rust_library_dylib", RustLibraryDylibFactory) 27 android.RegisterModuleType("rust_library_rlib", RustLibraryRlibFactory) 28 android.RegisterModuleType("rust_library_host", RustLibraryHostFactory) 29 android.RegisterModuleType("rust_library_host_dylib", RustLibraryDylibHostFactory) 30 android.RegisterModuleType("rust_library_host_rlib", RustLibraryRlibHostFactory) 31 android.RegisterModuleType("rust_ffi", RustFFIFactory) 32 android.RegisterModuleType("rust_ffi_shared", RustFFISharedFactory) 33 android.RegisterModuleType("rust_ffi_static", RustFFIStaticFactory) 34 android.RegisterModuleType("rust_ffi_host", RustFFIHostFactory) 35 android.RegisterModuleType("rust_ffi_host_shared", RustFFISharedHostFactory) 36 android.RegisterModuleType("rust_ffi_host_static", RustFFIStaticHostFactory) 37} 38 39type VariantLibraryProperties struct { 40 Enabled *bool `android:"arch_variant"` 41 Srcs []string `android:"path,arch_variant"` 42} 43 44type LibraryCompilerProperties struct { 45 Rlib VariantLibraryProperties `android:"arch_variant"` 46 Dylib VariantLibraryProperties `android:"arch_variant"` 47 Shared VariantLibraryProperties `android:"arch_variant"` 48 Static VariantLibraryProperties `android:"arch_variant"` 49 50 // path to include directories to pass to cc_* modules, only relevant for static/shared variants. 51 Include_dirs []string `android:"path,arch_variant"` 52} 53 54type LibraryMutatedProperties struct { 55 // Build a dylib variant 56 BuildDylib bool `blueprint:"mutated"` 57 // Build an rlib variant 58 BuildRlib bool `blueprint:"mutated"` 59 // Build a shared library variant 60 BuildShared bool `blueprint:"mutated"` 61 // Build a static library variant 62 BuildStatic bool `blueprint:"mutated"` 63 64 // This variant is a dylib 65 VariantIsDylib bool `blueprint:"mutated"` 66 // This variant is an rlib 67 VariantIsRlib bool `blueprint:"mutated"` 68 // This variant is a shared library 69 VariantIsShared bool `blueprint:"mutated"` 70 // This variant is a static library 71 VariantIsStatic bool `blueprint:"mutated"` 72} 73 74type libraryDecorator struct { 75 *baseCompiler 76 *flagExporter 77 78 Properties LibraryCompilerProperties 79 MutatedProperties LibraryMutatedProperties 80 includeDirs android.Paths 81} 82 83type libraryInterface interface { 84 rlib() bool 85 dylib() bool 86 static() bool 87 shared() bool 88 89 // Returns true if the build options for the module have selected a particular build type 90 buildRlib() bool 91 buildDylib() bool 92 buildShared() bool 93 buildStatic() bool 94 95 // Sets a particular variant type 96 setRlib() 97 setDylib() 98 setShared() 99 setStatic() 100 101 // Build a specific library variant 102 BuildOnlyFFI() 103 BuildOnlyRust() 104 BuildOnlyRlib() 105 BuildOnlyDylib() 106 BuildOnlyStatic() 107 BuildOnlyShared() 108} 109 110func (library *libraryDecorator) nativeCoverage() bool { 111 return true 112} 113 114func (library *libraryDecorator) rlib() bool { 115 return library.MutatedProperties.VariantIsRlib 116} 117 118func (library *libraryDecorator) dylib() bool { 119 return library.MutatedProperties.VariantIsDylib 120} 121 122func (library *libraryDecorator) shared() bool { 123 return library.MutatedProperties.VariantIsShared 124} 125 126func (library *libraryDecorator) static() bool { 127 return library.MutatedProperties.VariantIsStatic 128} 129 130func (library *libraryDecorator) buildRlib() bool { 131 return library.MutatedProperties.BuildRlib && BoolDefault(library.Properties.Rlib.Enabled, true) 132} 133 134func (library *libraryDecorator) buildDylib() bool { 135 return library.MutatedProperties.BuildDylib && BoolDefault(library.Properties.Dylib.Enabled, true) 136} 137 138func (library *libraryDecorator) buildShared() bool { 139 return library.MutatedProperties.BuildShared && BoolDefault(library.Properties.Shared.Enabled, true) 140} 141 142func (library *libraryDecorator) buildStatic() bool { 143 return library.MutatedProperties.BuildStatic && BoolDefault(library.Properties.Static.Enabled, true) 144} 145 146func (library *libraryDecorator) setRlib() { 147 library.MutatedProperties.VariantIsRlib = true 148 library.MutatedProperties.VariantIsDylib = false 149 library.MutatedProperties.VariantIsStatic = false 150 library.MutatedProperties.VariantIsShared = false 151} 152 153func (library *libraryDecorator) setDylib() { 154 library.MutatedProperties.VariantIsRlib = false 155 library.MutatedProperties.VariantIsDylib = true 156 library.MutatedProperties.VariantIsStatic = false 157 library.MutatedProperties.VariantIsShared = false 158} 159 160func (library *libraryDecorator) setShared() { 161 library.MutatedProperties.VariantIsStatic = false 162 library.MutatedProperties.VariantIsShared = true 163 library.MutatedProperties.VariantIsRlib = false 164 library.MutatedProperties.VariantIsDylib = false 165} 166 167func (library *libraryDecorator) setStatic() { 168 library.MutatedProperties.VariantIsStatic = true 169 library.MutatedProperties.VariantIsShared = false 170 library.MutatedProperties.VariantIsRlib = false 171 library.MutatedProperties.VariantIsDylib = false 172} 173 174func (library *libraryDecorator) autoDep() autoDep { 175 if library.rlib() || library.static() { 176 return rlibAutoDep 177 } else if library.dylib() || library.shared() { 178 return dylibAutoDep 179 } else { 180 return rlibAutoDep 181 } 182} 183 184var _ compiler = (*libraryDecorator)(nil) 185var _ libraryInterface = (*libraryDecorator)(nil) 186var _ exportedFlagsProducer = (*libraryDecorator)(nil) 187 188// rust_library produces all rust variants. 189func RustLibraryFactory() android.Module { 190 module, library := NewRustLibrary(android.HostAndDeviceSupported) 191 library.BuildOnlyRust() 192 return module.Init() 193} 194 195// rust_ffi produces all ffi variants. 196func RustFFIFactory() android.Module { 197 module, library := NewRustLibrary(android.HostAndDeviceSupported) 198 library.BuildOnlyFFI() 199 return module.Init() 200} 201 202// rust_library_dylib produces a dylib. 203func RustLibraryDylibFactory() android.Module { 204 module, library := NewRustLibrary(android.HostAndDeviceSupported) 205 library.BuildOnlyDylib() 206 return module.Init() 207} 208 209// rust_library_rlib produces an rlib. 210func RustLibraryRlibFactory() android.Module { 211 module, library := NewRustLibrary(android.HostAndDeviceSupported) 212 library.BuildOnlyRlib() 213 return module.Init() 214} 215 216// rust_ffi_shared produces a shared library. 217func RustFFISharedFactory() android.Module { 218 module, library := NewRustLibrary(android.HostAndDeviceSupported) 219 library.BuildOnlyShared() 220 return module.Init() 221} 222 223// rust_ffi_static produces a static library. 224func RustFFIStaticFactory() android.Module { 225 module, library := NewRustLibrary(android.HostAndDeviceSupported) 226 library.BuildOnlyStatic() 227 return module.Init() 228} 229 230// rust_library_host produces all rust variants. 231func RustLibraryHostFactory() android.Module { 232 module, library := NewRustLibrary(android.HostSupported) 233 library.BuildOnlyRust() 234 return module.Init() 235} 236 237// rust_ffi_host produces all FFI variants. 238func RustFFIHostFactory() android.Module { 239 module, library := NewRustLibrary(android.HostSupported) 240 library.BuildOnlyFFI() 241 return module.Init() 242} 243 244// rust_library_dylib_host produces a dylib. 245func RustLibraryDylibHostFactory() android.Module { 246 module, library := NewRustLibrary(android.HostSupported) 247 library.BuildOnlyDylib() 248 return module.Init() 249} 250 251// rust_library_rlib_host produces an rlib. 252func RustLibraryRlibHostFactory() android.Module { 253 module, library := NewRustLibrary(android.HostSupported) 254 library.BuildOnlyRlib() 255 return module.Init() 256} 257 258// rust_ffi_static_host produces a static library. 259func RustFFIStaticHostFactory() android.Module { 260 module, library := NewRustLibrary(android.HostSupported) 261 library.BuildOnlyStatic() 262 return module.Init() 263} 264 265// rust_ffi_shared_host produces an shared library. 266func RustFFISharedHostFactory() android.Module { 267 module, library := NewRustLibrary(android.HostSupported) 268 library.BuildOnlyShared() 269 return module.Init() 270} 271 272func (library *libraryDecorator) BuildOnlyFFI() { 273 library.MutatedProperties.BuildDylib = false 274 library.MutatedProperties.BuildRlib = false 275 library.MutatedProperties.BuildShared = true 276 library.MutatedProperties.BuildStatic = true 277} 278 279func (library *libraryDecorator) BuildOnlyRust() { 280 library.MutatedProperties.BuildDylib = true 281 library.MutatedProperties.BuildRlib = true 282 library.MutatedProperties.BuildShared = false 283 library.MutatedProperties.BuildStatic = false 284} 285 286func (library *libraryDecorator) BuildOnlyDylib() { 287 library.MutatedProperties.BuildDylib = true 288 library.MutatedProperties.BuildRlib = false 289 library.MutatedProperties.BuildShared = false 290 library.MutatedProperties.BuildStatic = false 291} 292 293func (library *libraryDecorator) BuildOnlyRlib() { 294 library.MutatedProperties.BuildDylib = false 295 library.MutatedProperties.BuildRlib = true 296 library.MutatedProperties.BuildShared = false 297 library.MutatedProperties.BuildStatic = false 298} 299 300func (library *libraryDecorator) BuildOnlyStatic() { 301 library.MutatedProperties.BuildRlib = false 302 library.MutatedProperties.BuildDylib = false 303 library.MutatedProperties.BuildShared = false 304 library.MutatedProperties.BuildStatic = true 305} 306 307func (library *libraryDecorator) BuildOnlyShared() { 308 library.MutatedProperties.BuildRlib = false 309 library.MutatedProperties.BuildDylib = false 310 library.MutatedProperties.BuildStatic = false 311 library.MutatedProperties.BuildShared = true 312} 313 314func NewRustLibrary(hod android.HostOrDeviceSupported) (*Module, *libraryDecorator) { 315 module := newModule(hod, android.MultilibBoth) 316 317 library := &libraryDecorator{ 318 MutatedProperties: LibraryMutatedProperties{ 319 BuildDylib: false, 320 BuildRlib: false, 321 BuildShared: false, 322 BuildStatic: false, 323 }, 324 baseCompiler: NewBaseCompiler("lib", "lib64", InstallInSystem), 325 flagExporter: NewFlagExporter(), 326 } 327 328 module.compiler = library 329 330 return module, library 331} 332 333func (library *libraryDecorator) compilerProps() []interface{} { 334 return append(library.baseCompiler.compilerProps(), 335 &library.Properties, 336 &library.MutatedProperties) 337} 338 339func (library *libraryDecorator) compilerDeps(ctx DepsContext, deps Deps) Deps { 340 deps = library.baseCompiler.compilerDeps(ctx, deps) 341 342 if ctx.toolchain().Bionic() && (library.dylib() || library.shared()) { 343 deps = bionicDeps(deps) 344 deps.CrtBegin = "crtbegin_so" 345 deps.CrtEnd = "crtend_so" 346 } 347 348 return deps 349} 350 351func (library *libraryDecorator) sharedLibFilename(ctx ModuleContext) string { 352 return library.getStem(ctx) + ctx.toolchain().SharedLibSuffix() 353} 354 355func (library *libraryDecorator) compilerFlags(ctx ModuleContext, flags Flags) Flags { 356 flags.RustFlags = append(flags.RustFlags, "-C metadata="+ctx.ModuleName()) 357 flags = library.baseCompiler.compilerFlags(ctx, flags) 358 if library.shared() || library.static() { 359 library.includeDirs = append(library.includeDirs, android.PathsForModuleSrc(ctx, library.Properties.Include_dirs)...) 360 } 361 if library.shared() { 362 flags.LinkFlags = append(flags.LinkFlags, "-Wl,-soname="+library.sharedLibFilename(ctx)) 363 } 364 365 return flags 366} 367 368func (library *libraryDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) android.Path { 369 var outputFile android.WritablePath 370 371 srcPath, _ := srcPathFromModuleSrcs(ctx, library.baseCompiler.Properties.Srcs) 372 373 flags.RustFlags = append(flags.RustFlags, deps.depFlags...) 374 375 if library.dylib() { 376 // We need prefer-dynamic for now to avoid linking in the static stdlib. See: 377 // https://github.com/rust-lang/rust/issues/19680 378 // https://github.com/rust-lang/rust/issues/34909 379 flags.RustFlags = append(flags.RustFlags, "-C prefer-dynamic") 380 } 381 382 if library.rlib() { 383 fileName := library.getStem(ctx) + ctx.toolchain().RlibSuffix() 384 outputFile = android.PathForModuleOut(ctx, fileName) 385 386 outputs := TransformSrctoRlib(ctx, srcPath, deps, flags, outputFile, deps.linkDirs) 387 library.coverageFile = outputs.coverageFile 388 } else if library.dylib() { 389 fileName := library.getStem(ctx) + ctx.toolchain().DylibSuffix() 390 outputFile = android.PathForModuleOut(ctx, fileName) 391 392 outputs := TransformSrctoDylib(ctx, srcPath, deps, flags, outputFile, deps.linkDirs) 393 library.coverageFile = outputs.coverageFile 394 } else if library.static() { 395 fileName := library.getStem(ctx) + ctx.toolchain().StaticLibSuffix() 396 outputFile = android.PathForModuleOut(ctx, fileName) 397 398 outputs := TransformSrctoStatic(ctx, srcPath, deps, flags, outputFile, deps.linkDirs) 399 library.coverageFile = outputs.coverageFile 400 } else if library.shared() { 401 fileName := library.sharedLibFilename(ctx) 402 outputFile = android.PathForModuleOut(ctx, fileName) 403 404 outputs := TransformSrctoShared(ctx, srcPath, deps, flags, outputFile, deps.linkDirs) 405 library.coverageFile = outputs.coverageFile 406 } 407 408 var coverageFiles android.Paths 409 if library.coverageFile != nil { 410 coverageFiles = append(coverageFiles, library.coverageFile) 411 } 412 if len(deps.coverageFiles) > 0 { 413 coverageFiles = append(coverageFiles, deps.coverageFiles...) 414 } 415 library.coverageOutputZipFile = TransformCoverageFilesToZip(ctx, coverageFiles, library.getStem(ctx)) 416 417 if library.rlib() || library.dylib() { 418 library.exportLinkDirs(deps.linkDirs...) 419 library.exportDepFlags(deps.depFlags...) 420 } 421 library.unstrippedOutputFile = outputFile 422 423 return outputFile 424} 425 426func (library *libraryDecorator) getStem(ctx ModuleContext) string { 427 stem := library.baseCompiler.getStemWithoutSuffix(ctx) 428 validateLibraryStem(ctx, stem, library.crateName()) 429 430 return stem + String(library.baseCompiler.Properties.Suffix) 431} 432 433var validCrateName = regexp.MustCompile("[^a-zA-Z0-9_]+") 434 435func validateLibraryStem(ctx BaseModuleContext, filename string, crate_name string) { 436 if crate_name == "" { 437 ctx.PropertyErrorf("crate_name", "crate_name must be defined.") 438 } 439 440 // crate_names are used for the library output file, and rustc expects these 441 // to be alphanumeric with underscores allowed. 442 if validCrateName.MatchString(crate_name) { 443 ctx.PropertyErrorf("crate_name", 444 "library crate_names must be alphanumeric with underscores allowed") 445 } 446 447 // Libraries are expected to begin with "lib" followed by the crate_name 448 if !strings.HasPrefix(filename, "lib"+crate_name) { 449 ctx.ModuleErrorf("Invalid name or stem property; library filenames must start with lib<crate_name>") 450 } 451} 452 453func LibraryMutator(mctx android.BottomUpMutatorContext) { 454 if m, ok := mctx.Module().(*Module); ok && m.compiler != nil { 455 switch library := m.compiler.(type) { 456 case libraryInterface: 457 if library.buildRlib() && library.buildDylib() { 458 modules := mctx.CreateLocalVariations("rlib", "dylib") 459 rlib := modules[0].(*Module) 460 dylib := modules[1].(*Module) 461 462 rlib.compiler.(libraryInterface).setRlib() 463 dylib.compiler.(libraryInterface).setDylib() 464 } else if library.buildRlib() { 465 modules := mctx.CreateLocalVariations("rlib") 466 modules[0].(*Module).compiler.(libraryInterface).setRlib() 467 } else if library.buildDylib() { 468 modules := mctx.CreateLocalVariations("dylib") 469 modules[0].(*Module).compiler.(libraryInterface).setDylib() 470 } 471 } 472 } 473} 474