1// Copyright 2019 Google Inc. All rights reserved. 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 cc 16 17import ( 18 "path/filepath" 19 20 "android/soong/android" 21 22 "github.com/google/blueprint" 23 "github.com/google/blueprint/proptools" 24) 25 26// This file contains support for using cc library modules within an sdk. 27 28var sharedLibrarySdkMemberType = &librarySdkMemberType{ 29 SdkMemberTypeBase: android.SdkMemberTypeBase{ 30 PropertyName: "native_shared_libs", 31 SupportsSdk: true, 32 HostOsDependent: true, 33 }, 34 prebuiltModuleType: "cc_prebuilt_library_shared", 35 linkTypes: []string{"shared"}, 36} 37 38var staticLibrarySdkMemberType = &librarySdkMemberType{ 39 SdkMemberTypeBase: android.SdkMemberTypeBase{ 40 PropertyName: "native_static_libs", 41 SupportsSdk: true, 42 HostOsDependent: true, 43 }, 44 prebuiltModuleType: "cc_prebuilt_library_static", 45 linkTypes: []string{"static"}, 46} 47 48var staticAndSharedLibrarySdkMemberType = &librarySdkMemberType{ 49 SdkMemberTypeBase: android.SdkMemberTypeBase{ 50 PropertyName: "native_libs", 51 SupportsSdk: true, 52 HostOsDependent: true, 53 }, 54 prebuiltModuleType: "cc_prebuilt_library", 55 linkTypes: []string{"static", "shared"}, 56} 57 58func init() { 59 // Register sdk member types. 60 android.RegisterSdkMemberType(sharedLibrarySdkMemberType) 61 android.RegisterSdkMemberType(staticLibrarySdkMemberType) 62 android.RegisterSdkMemberType(staticAndSharedLibrarySdkMemberType) 63} 64 65type librarySdkMemberType struct { 66 android.SdkMemberTypeBase 67 68 prebuiltModuleType string 69 70 noOutputFiles bool // True if there are no srcs files. 71 72 // The set of link types supported. A set of "static", "shared", or nil to 73 // skip link type variations. 74 linkTypes []string 75} 76 77func (mt *librarySdkMemberType) AddDependencies(mctx android.BottomUpMutatorContext, dependencyTag blueprint.DependencyTag, names []string) { 78 targets := mctx.MultiTargets() 79 for _, lib := range names { 80 for _, target := range targets { 81 name, version := StubsLibNameAndVersion(lib) 82 if version == "" { 83 version = "latest" 84 } 85 variations := target.Variations() 86 if mctx.Device() { 87 variations = append(variations, 88 blueprint.Variation{Mutator: "image", Variation: android.CoreVariation}) 89 } 90 if mt.linkTypes == nil { 91 mctx.AddFarVariationDependencies(variations, dependencyTag, name) 92 } else { 93 for _, linkType := range mt.linkTypes { 94 libVariations := append(variations, 95 blueprint.Variation{Mutator: "link", Variation: linkType}) 96 if mctx.Device() && linkType == "shared" { 97 libVariations = append(libVariations, 98 blueprint.Variation{Mutator: "version", Variation: version}) 99 } 100 mctx.AddFarVariationDependencies(libVariations, dependencyTag, name) 101 } 102 } 103 } 104 } 105} 106 107func (mt *librarySdkMemberType) IsInstance(module android.Module) bool { 108 // Check the module to see if it can be used with this module type. 109 if m, ok := module.(*Module); ok { 110 for _, allowableMemberType := range m.sdkMemberTypes { 111 if allowableMemberType == mt { 112 return true 113 } 114 } 115 } 116 117 return false 118} 119 120func (mt *librarySdkMemberType) AddPrebuiltModule(ctx android.SdkMemberContext, member android.SdkMember) android.BpModule { 121 pbm := ctx.SnapshotBuilder().AddPrebuiltModule(member, mt.prebuiltModuleType) 122 123 ccModule := member.Variants()[0].(*Module) 124 125 if proptools.Bool(ccModule.Properties.Recovery_available) { 126 pbm.AddProperty("recovery_available", true) 127 } 128 129 if proptools.Bool(ccModule.VendorProperties.Vendor_available) { 130 pbm.AddProperty("vendor_available", true) 131 } 132 133 if proptools.Bool(ccModule.VendorProperties.Odm_available) { 134 pbm.AddProperty("odm_available", true) 135 } 136 137 if proptools.Bool(ccModule.VendorProperties.Product_available) { 138 pbm.AddProperty("product_available", true) 139 } 140 141 sdkVersion := ccModule.SdkVersion() 142 if sdkVersion != "" { 143 pbm.AddProperty("sdk_version", sdkVersion) 144 } 145 146 stl := ccModule.stl.Properties.Stl 147 if stl != nil { 148 pbm.AddProperty("stl", proptools.String(stl)) 149 } 150 151 if lib, ok := ccModule.linker.(*libraryDecorator); ok { 152 uhs := lib.Properties.Unique_host_soname 153 if uhs != nil { 154 pbm.AddProperty("unique_host_soname", proptools.Bool(uhs)) 155 } 156 } 157 158 return pbm 159} 160 161func (mt *librarySdkMemberType) CreateVariantPropertiesStruct() android.SdkMemberProperties { 162 return &nativeLibInfoProperties{memberType: mt} 163} 164 165func isBazelOutDirectory(p android.Path) bool { 166 _, bazel := p.(android.BazelOutPath) 167 return bazel 168} 169 170func isGeneratedHeaderDirectory(p android.Path) bool { 171 _, gen := p.(android.WritablePath) 172 // TODO(b/183213331): Here we assume that bazel-based headers are not generated; we need 173 // to support generated headers in mixed builds. 174 return gen && !isBazelOutDirectory(p) 175} 176 177type includeDirsProperty struct { 178 // Accessor to retrieve the paths 179 pathsGetter func(libInfo *nativeLibInfoProperties) android.Paths 180 181 // The name of the property in the prebuilt library, "" means there is no property. 182 propertyName string 183 184 // The directory within the snapshot directory into which items should be copied. 185 snapshotDir string 186 187 // True if the items on the path should be copied. 188 copy bool 189 190 // True if the paths represent directories, files if they represent files. 191 dirs bool 192} 193 194var includeDirProperties = []includeDirsProperty{ 195 { 196 // ExportedIncludeDirs lists directories that contains some header files to be 197 // copied into a directory in the snapshot. The snapshot directories must be added to 198 // the export_include_dirs property in the prebuilt module in the snapshot. 199 pathsGetter: func(libInfo *nativeLibInfoProperties) android.Paths { return libInfo.ExportedIncludeDirs }, 200 propertyName: "export_include_dirs", 201 snapshotDir: nativeIncludeDir, 202 copy: true, 203 dirs: true, 204 }, 205 { 206 // ExportedSystemIncludeDirs lists directories that contains some system header files to 207 // be copied into a directory in the snapshot. The snapshot directories must be added to 208 // the export_system_include_dirs property in the prebuilt module in the snapshot. 209 pathsGetter: func(libInfo *nativeLibInfoProperties) android.Paths { return libInfo.ExportedSystemIncludeDirs }, 210 propertyName: "export_system_include_dirs", 211 snapshotDir: nativeIncludeDir, 212 copy: true, 213 dirs: true, 214 }, 215 { 216 // ExportedGeneratedIncludeDirs lists directories that contains some header files 217 // that are explicitly listed in the ExportedGeneratedHeaders property. So, the contents 218 // of these directories do not need to be copied, but these directories do need adding to 219 // the export_include_dirs property in the prebuilt module in the snapshot. 220 pathsGetter: func(libInfo *nativeLibInfoProperties) android.Paths { return libInfo.ExportedGeneratedIncludeDirs }, 221 propertyName: "export_include_dirs", 222 snapshotDir: nativeGeneratedIncludeDir, 223 copy: false, 224 dirs: true, 225 }, 226 { 227 // ExportedGeneratedHeaders lists header files that are in one of the directories 228 // specified in ExportedGeneratedIncludeDirs must be copied into the snapshot. 229 // As they are in a directory in ExportedGeneratedIncludeDirs they do not need adding to a 230 // property in the prebuilt module in the snapshot. 231 pathsGetter: func(libInfo *nativeLibInfoProperties) android.Paths { return libInfo.ExportedGeneratedHeaders }, 232 propertyName: "", 233 snapshotDir: nativeGeneratedIncludeDir, 234 copy: true, 235 dirs: false, 236 }, 237} 238 239// Add properties that may, or may not, be arch specific. 240func addPossiblyArchSpecificProperties(sdkModuleContext android.ModuleContext, builder android.SnapshotBuilder, libInfo *nativeLibInfoProperties, outputProperties android.BpPropertySet) { 241 242 outputProperties.AddProperty("sanitize", &libInfo.Sanitize) 243 244 // Copy the generated library to the snapshot and add a reference to it in the .bp module. 245 if libInfo.outputFile != nil { 246 nativeLibraryPath := nativeLibraryPathFor(libInfo) 247 builder.CopyToSnapshot(libInfo.outputFile, nativeLibraryPath) 248 outputProperties.AddProperty("srcs", []string{nativeLibraryPath}) 249 } 250 251 if len(libInfo.SharedLibs) > 0 { 252 outputProperties.AddPropertyWithTag("shared_libs", libInfo.SharedLibs, builder.SdkMemberReferencePropertyTag(false)) 253 } 254 255 // SystemSharedLibs needs to be propagated if it's a list, even if it's empty, 256 // so check for non-nil instead of nonzero length. 257 if libInfo.SystemSharedLibs != nil { 258 outputProperties.AddPropertyWithTag("system_shared_libs", libInfo.SystemSharedLibs, builder.SdkMemberReferencePropertyTag(false)) 259 } 260 261 // Map from property name to the include dirs to add to the prebuilt module in the snapshot. 262 includeDirs := make(map[string][]string) 263 264 // Iterate over each include directory property, copying files and collating property 265 // values where necessary. 266 for _, propertyInfo := range includeDirProperties { 267 // Calculate the base directory in the snapshot into which the files will be copied. 268 // lib.archType is "" for common properties. 269 targetDir := filepath.Join(libInfo.OsPrefix(), libInfo.archType, propertyInfo.snapshotDir) 270 271 propertyName := propertyInfo.propertyName 272 273 // Iterate over each path in one of the include directory properties. 274 for _, path := range propertyInfo.pathsGetter(libInfo) { 275 inputPath := path.String() 276 277 // Map the input path to a snapshot relative path. The mapping is independent of the module 278 // that references them so that if multiple modules within the same snapshot export the same 279 // header files they end up in the same place in the snapshot and so do not get duplicated. 280 targetRelativePath := inputPath 281 if isGeneratedHeaderDirectory(path) { 282 // Remove everything up to the .intermediates/ from the generated output directory to 283 // leave a module relative path. 284 base := android.PathForIntermediates(sdkModuleContext, "") 285 targetRelativePath = android.Rel(sdkModuleContext, base.String(), inputPath) 286 } 287 288 snapshotRelativePath := filepath.Join(targetDir, targetRelativePath) 289 290 // Copy the files/directories when necessary. 291 if propertyInfo.copy { 292 if propertyInfo.dirs { 293 // When copying a directory glob and copy all the headers within it. 294 // TODO(jiyong) copy headers having other suffixes 295 headers, _ := sdkModuleContext.GlobWithDeps(inputPath+"/**/*.h", nil) 296 for _, file := range headers { 297 src := android.PathForSource(sdkModuleContext, file) 298 299 // The destination path in the snapshot is constructed from the snapshot relative path 300 // of the input directory and the input directory relative path of the header file. 301 inputRelativePath := android.Rel(sdkModuleContext, inputPath, file) 302 dest := filepath.Join(snapshotRelativePath, inputRelativePath) 303 builder.CopyToSnapshot(src, dest) 304 } 305 } else { 306 // Otherwise, just copy the file to its snapshot relative path. 307 builder.CopyToSnapshot(path, snapshotRelativePath) 308 } 309 } 310 311 // Only directories are added to a property. 312 if propertyInfo.dirs { 313 includeDirs[propertyName] = append(includeDirs[propertyName], snapshotRelativePath) 314 } 315 } 316 } 317 318 // Add the collated include dir properties to the output. 319 for _, property := range android.SortedStringKeys(includeDirs) { 320 outputProperties.AddProperty(property, includeDirs[property]) 321 } 322 323 if len(libInfo.StubsVersions) > 0 { 324 stubsSet := outputProperties.AddPropertySet("stubs") 325 stubsSet.AddProperty("versions", libInfo.StubsVersions) 326 } 327} 328 329const ( 330 nativeIncludeDir = "include" 331 nativeGeneratedIncludeDir = "include_gen" 332 nativeStubDir = "lib" 333) 334 335// path to the native library. Relative to <sdk_root>/<api_dir> 336func nativeLibraryPathFor(lib *nativeLibInfoProperties) string { 337 return filepath.Join(lib.OsPrefix(), lib.archType, 338 nativeStubDir, lib.outputFile.Base()) 339} 340 341// nativeLibInfoProperties represents properties of a native lib 342// 343// The exported (capitalized) fields will be examined and may be changed during common value extraction. 344// The unexported fields will be left untouched. 345type nativeLibInfoProperties struct { 346 android.SdkMemberPropertiesBase 347 348 memberType *librarySdkMemberType 349 350 // archType is not exported as if set (to a non default value) it is always arch specific. 351 // This is "" for common properties. 352 archType string 353 354 // The list of possibly common exported include dirs. 355 // 356 // This field is exported as its contents may not be arch specific. 357 ExportedIncludeDirs android.Paths `android:"arch_variant"` 358 359 // The list of arch specific exported generated include dirs. 360 // 361 // This field is exported as its contents may not be arch specific, e.g. protos. 362 ExportedGeneratedIncludeDirs android.Paths `android:"arch_variant"` 363 364 // The list of arch specific exported generated header files. 365 // 366 // This field is exported as its contents may not be arch specific, e.g. protos. 367 ExportedGeneratedHeaders android.Paths `android:"arch_variant"` 368 369 // The list of possibly common exported system include dirs. 370 // 371 // This field is exported as its contents may not be arch specific. 372 ExportedSystemIncludeDirs android.Paths `android:"arch_variant"` 373 374 // The list of possibly common exported flags. 375 // 376 // This field is exported as its contents may not be arch specific. 377 ExportedFlags []string `android:"arch_variant"` 378 379 // The set of shared libraries 380 // 381 // This field is exported as its contents may not be arch specific. 382 SharedLibs []string `android:"arch_variant"` 383 384 // The set of system shared libraries. Note nil and [] are semantically 385 // distinct - see BaseLinkerProperties.System_shared_libs. 386 // 387 // This field is exported as its contents may not be arch specific. 388 SystemSharedLibs []string `android:"arch_variant"` 389 390 // The specific stubs version for the lib variant, or empty string if stubs 391 // are not in use. 392 // 393 // Marked 'ignored-on-host' as the AllStubsVersions() from which this is 394 // initialized is not set on host and the stubs.versions property which this 395 // is written to does not vary by arch so cannot be android specific. 396 StubsVersions []string `sdk:"ignored-on-host"` 397 398 // Value of SanitizeProperties.Sanitize. Several - but not all - of these 399 // affect the expanded variants. All are propagated to avoid entangling the 400 // sanitizer logic with the snapshot generation. 401 Sanitize SanitizeUserProps `android:"arch_variant"` 402 403 // outputFile is not exported as it is always arch specific. 404 outputFile android.Path 405} 406 407func (p *nativeLibInfoProperties) PopulateFromVariant(ctx android.SdkMemberContext, variant android.Module) { 408 addOutputFile := true 409 ccModule := variant.(*Module) 410 411 if s := ccModule.sanitize; s != nil { 412 // We currently do not capture sanitizer flags for libs with sanitizers 413 // enabled, because they may vary among variants that cannot be represented 414 // in the input blueprint files. In particular, sanitizerDepsMutator enables 415 // various sanitizers on dependencies, but in many cases only on static 416 // ones, and we cannot specify sanitizer flags at the link type level (i.e. 417 // in StaticOrSharedProperties). 418 if s.isUnsanitizedVariant() { 419 // This still captures explicitly disabled sanitizers, which may be 420 // necessary to avoid cyclic dependencies. 421 p.Sanitize = s.Properties.Sanitize 422 } else { 423 // Do not add the output file to the snapshot if we don't represent it 424 // properly. 425 addOutputFile = false 426 } 427 } 428 429 exportedInfo := ctx.SdkModuleContext().OtherModuleProvider(variant, FlagExporterInfoProvider).(FlagExporterInfo) 430 431 // Separate out the generated include dirs (which are arch specific) from the 432 // include dirs (which may not be). 433 exportedIncludeDirs, exportedGeneratedIncludeDirs := android.FilterPathListPredicate( 434 exportedInfo.IncludeDirs, isGeneratedHeaderDirectory) 435 436 p.archType = ccModule.Target().Arch.ArchType.String() 437 438 // Make sure that the include directories are unique. 439 p.ExportedIncludeDirs = android.FirstUniquePaths(exportedIncludeDirs) 440 p.ExportedGeneratedIncludeDirs = android.FirstUniquePaths(exportedGeneratedIncludeDirs) 441 442 // Take a copy before filtering out duplicates to avoid changing the slice owned by the 443 // ccModule. 444 dirs := append(android.Paths(nil), exportedInfo.SystemIncludeDirs...) 445 p.ExportedSystemIncludeDirs = android.FirstUniquePaths(dirs) 446 447 p.ExportedFlags = exportedInfo.Flags 448 if ccModule.linker != nil { 449 specifiedDeps := specifiedDeps{} 450 specifiedDeps = ccModule.linker.linkerSpecifiedDeps(specifiedDeps) 451 452 if lib := ccModule.library; lib != nil { 453 if !lib.hasStubsVariants() { 454 // Propagate dynamic dependencies for implementation libs, but not stubs. 455 p.SharedLibs = specifiedDeps.sharedLibs 456 } else { 457 // TODO(b/169373910): 1. Only output the specific version (from 458 // ccModule.StubsVersion()) if the module is versioned. 2. Ensure that all 459 // the versioned stub libs are retained in the prebuilt tree; currently only 460 // the stub corresponding to ccModule.StubsVersion() is. 461 p.StubsVersions = lib.allStubsVersions() 462 } 463 } 464 p.SystemSharedLibs = specifiedDeps.systemSharedLibs 465 } 466 p.ExportedGeneratedHeaders = exportedInfo.GeneratedHeaders 467 468 if !p.memberType.noOutputFiles && addOutputFile { 469 p.outputFile = getRequiredMemberOutputFile(ctx, ccModule) 470 } 471} 472 473func getRequiredMemberOutputFile(ctx android.SdkMemberContext, ccModule *Module) android.Path { 474 var path android.Path 475 outputFile := ccModule.OutputFile() 476 if outputFile.Valid() { 477 path = outputFile.Path() 478 } else { 479 ctx.SdkModuleContext().ModuleErrorf("member variant %s does not have a valid output file", ccModule) 480 } 481 return path 482} 483 484func (p *nativeLibInfoProperties) AddToPropertySet(ctx android.SdkMemberContext, propertySet android.BpPropertySet) { 485 addPossiblyArchSpecificProperties(ctx.SdkModuleContext(), ctx.SnapshotBuilder(), p, propertySet) 486} 487