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 }, 33 prebuiltModuleType: "cc_prebuilt_library_shared", 34 linkTypes: []string{"shared"}, 35} 36 37var staticLibrarySdkMemberType = &librarySdkMemberType{ 38 SdkMemberTypeBase: android.SdkMemberTypeBase{ 39 PropertyName: "native_static_libs", 40 SupportsSdk: true, 41 }, 42 prebuiltModuleType: "cc_prebuilt_library_static", 43 linkTypes: []string{"static"}, 44} 45 46var staticAndSharedLibrarySdkMemberType = &librarySdkMemberType{ 47 SdkMemberTypeBase: android.SdkMemberTypeBase{ 48 PropertyName: "native_libs", 49 SupportsSdk: true, 50 }, 51 prebuiltModuleType: "cc_prebuilt_library", 52 linkTypes: []string{"static", "shared"}, 53} 54 55func init() { 56 // Register sdk member types. 57 android.RegisterSdkMemberType(sharedLibrarySdkMemberType) 58 android.RegisterSdkMemberType(staticLibrarySdkMemberType) 59 android.RegisterSdkMemberType(staticAndSharedLibrarySdkMemberType) 60} 61 62type librarySdkMemberType struct { 63 android.SdkMemberTypeBase 64 65 prebuiltModuleType string 66 67 noOutputFiles bool // True if there are no srcs files. 68 69 // The set of link types supported. A set of "static", "shared", or nil to 70 // skip link type variations. 71 linkTypes []string 72} 73 74func (mt *librarySdkMemberType) AddDependencies(mctx android.BottomUpMutatorContext, dependencyTag blueprint.DependencyTag, names []string) { 75 targets := mctx.MultiTargets() 76 for _, lib := range names { 77 for _, target := range targets { 78 name, version := StubsLibNameAndVersion(lib) 79 if version == "" { 80 version = LatestStubsVersionFor(mctx.Config(), name) 81 } 82 if mt.linkTypes == nil { 83 mctx.AddFarVariationDependencies(append(target.Variations(), []blueprint.Variation{ 84 {Mutator: "image", Variation: android.CoreVariation}, 85 {Mutator: "version", Variation: version}, 86 }...), dependencyTag, name) 87 } else { 88 for _, linkType := range mt.linkTypes { 89 mctx.AddFarVariationDependencies(append(target.Variations(), []blueprint.Variation{ 90 {Mutator: "image", Variation: android.CoreVariation}, 91 {Mutator: "link", Variation: linkType}, 92 {Mutator: "version", Variation: version}, 93 }...), dependencyTag, name) 94 } 95 } 96 } 97 } 98} 99 100func (mt *librarySdkMemberType) IsInstance(module android.Module) bool { 101 // Check the module to see if it can be used with this module type. 102 if m, ok := module.(*Module); ok { 103 for _, allowableMemberType := range m.sdkMemberTypes { 104 if allowableMemberType == mt { 105 return true 106 } 107 } 108 } 109 110 return false 111} 112 113func (mt *librarySdkMemberType) AddPrebuiltModule(ctx android.SdkMemberContext, member android.SdkMember) android.BpModule { 114 pbm := ctx.SnapshotBuilder().AddPrebuiltModule(member, mt.prebuiltModuleType) 115 116 ccModule := member.Variants()[0].(*Module) 117 118 sdkVersion := ccModule.SdkVersion() 119 if sdkVersion != "" { 120 pbm.AddProperty("sdk_version", sdkVersion) 121 } 122 123 stl := ccModule.stl.Properties.Stl 124 if stl != nil { 125 pbm.AddProperty("stl", proptools.String(stl)) 126 } 127 128 if lib, ok := ccModule.linker.(*libraryDecorator); ok { 129 uhs := lib.Properties.Unique_host_soname 130 if uhs != nil { 131 pbm.AddProperty("unique_host_soname", proptools.Bool(uhs)) 132 } 133 } 134 135 return pbm 136} 137 138func (mt *librarySdkMemberType) CreateVariantPropertiesStruct() android.SdkMemberProperties { 139 return &nativeLibInfoProperties{memberType: mt} 140} 141 142func isGeneratedHeaderDirectory(p android.Path) bool { 143 _, gen := p.(android.WritablePath) 144 return gen 145} 146 147type includeDirsProperty struct { 148 // Accessor to retrieve the paths 149 pathsGetter func(libInfo *nativeLibInfoProperties) android.Paths 150 151 // The name of the property in the prebuilt library, "" means there is no property. 152 propertyName string 153 154 // The directory within the snapshot directory into which items should be copied. 155 snapshotDir string 156 157 // True if the items on the path should be copied. 158 copy bool 159 160 // True if the paths represent directories, files if they represent files. 161 dirs bool 162} 163 164var includeDirProperties = []includeDirsProperty{ 165 { 166 // ExportedIncludeDirs lists directories that contains some header files to be 167 // copied into a directory in the snapshot. The snapshot directories must be added to 168 // the export_include_dirs property in the prebuilt module in the snapshot. 169 pathsGetter: func(libInfo *nativeLibInfoProperties) android.Paths { return libInfo.ExportedIncludeDirs }, 170 propertyName: "export_include_dirs", 171 snapshotDir: nativeIncludeDir, 172 copy: true, 173 dirs: true, 174 }, 175 { 176 // ExportedSystemIncludeDirs lists directories that contains some system header files to 177 // be copied into a directory in the snapshot. The snapshot directories must be added to 178 // the export_system_include_dirs property in the prebuilt module in the snapshot. 179 pathsGetter: func(libInfo *nativeLibInfoProperties) android.Paths { return libInfo.ExportedSystemIncludeDirs }, 180 propertyName: "export_system_include_dirs", 181 snapshotDir: nativeIncludeDir, 182 copy: true, 183 dirs: true, 184 }, 185 { 186 // exportedGeneratedIncludeDirs lists directories that contains some header files 187 // that are explicitly listed in the exportedGeneratedHeaders property. So, the contents 188 // of these directories do not need to be copied, but these directories do need adding to 189 // the export_include_dirs property in the prebuilt module in the snapshot. 190 pathsGetter: func(libInfo *nativeLibInfoProperties) android.Paths { return libInfo.exportedGeneratedIncludeDirs }, 191 propertyName: "export_include_dirs", 192 snapshotDir: nativeGeneratedIncludeDir, 193 copy: false, 194 dirs: true, 195 }, 196 { 197 // exportedGeneratedHeaders lists header files that are in one of the directories 198 // specified in exportedGeneratedIncludeDirs must be copied into the snapshot. 199 // As they are in a directory in exportedGeneratedIncludeDirs they do not need adding to a 200 // property in the prebuilt module in the snapshot. 201 pathsGetter: func(libInfo *nativeLibInfoProperties) android.Paths { return libInfo.exportedGeneratedHeaders }, 202 propertyName: "", 203 snapshotDir: nativeGeneratedIncludeDir, 204 copy: true, 205 dirs: false, 206 }, 207} 208 209// Add properties that may, or may not, be arch specific. 210func addPossiblyArchSpecificProperties(sdkModuleContext android.ModuleContext, builder android.SnapshotBuilder, libInfo *nativeLibInfoProperties, outputProperties android.BpPropertySet) { 211 212 // Copy the generated library to the snapshot and add a reference to it in the .bp module. 213 if libInfo.outputFile != nil { 214 nativeLibraryPath := nativeLibraryPathFor(libInfo) 215 builder.CopyToSnapshot(libInfo.outputFile, nativeLibraryPath) 216 outputProperties.AddProperty("srcs", []string{nativeLibraryPath}) 217 } 218 219 if len(libInfo.SharedLibs) > 0 { 220 outputProperties.AddPropertyWithTag("shared_libs", libInfo.SharedLibs, builder.SdkMemberReferencePropertyTag(false)) 221 } 222 223 // SystemSharedLibs needs to be propagated if it's a list, even if it's empty, 224 // so check for non-nil instead of nonzero length. 225 if libInfo.SystemSharedLibs != nil { 226 outputProperties.AddPropertyWithTag("system_shared_libs", libInfo.SystemSharedLibs, builder.SdkMemberReferencePropertyTag(false)) 227 } 228 229 // Map from property name to the include dirs to add to the prebuilt module in the snapshot. 230 includeDirs := make(map[string][]string) 231 232 // Iterate over each include directory property, copying files and collating property 233 // values where necessary. 234 for _, propertyInfo := range includeDirProperties { 235 // Calculate the base directory in the snapshot into which the files will be copied. 236 // lib.ArchType is "" for common properties. 237 targetDir := filepath.Join(libInfo.OsPrefix(), libInfo.archType, propertyInfo.snapshotDir) 238 239 propertyName := propertyInfo.propertyName 240 241 // Iterate over each path in one of the include directory properties. 242 for _, path := range propertyInfo.pathsGetter(libInfo) { 243 244 // Copy the files/directories when necessary. 245 if propertyInfo.copy { 246 if propertyInfo.dirs { 247 // When copying a directory glob and copy all the headers within it. 248 // TODO(jiyong) copy headers having other suffixes 249 headers, _ := sdkModuleContext.GlobWithDeps(path.String()+"/**/*.h", nil) 250 for _, file := range headers { 251 src := android.PathForSource(sdkModuleContext, file) 252 dest := filepath.Join(targetDir, file) 253 builder.CopyToSnapshot(src, dest) 254 } 255 } else { 256 // Otherwise, just copy the files. 257 dest := filepath.Join(targetDir, libInfo.name, path.Rel()) 258 builder.CopyToSnapshot(path, dest) 259 } 260 } 261 262 // Only directories are added to a property. 263 if propertyInfo.dirs { 264 var snapshotPath string 265 if isGeneratedHeaderDirectory(path) { 266 snapshotPath = filepath.Join(targetDir, libInfo.name) 267 } else { 268 snapshotPath = filepath.Join(targetDir, path.String()) 269 } 270 271 includeDirs[propertyName] = append(includeDirs[propertyName], snapshotPath) 272 } 273 } 274 } 275 276 // Add the collated include dir properties to the output. 277 for property, dirs := range includeDirs { 278 outputProperties.AddProperty(property, dirs) 279 } 280 281 if len(libInfo.StubsVersion) > 0 { 282 stubsSet := outputProperties.AddPropertySet("stubs") 283 stubsSet.AddProperty("versions", []string{libInfo.StubsVersion}) 284 } 285} 286 287const ( 288 nativeIncludeDir = "include" 289 nativeGeneratedIncludeDir = "include_gen" 290 nativeStubDir = "lib" 291) 292 293// path to the native library. Relative to <sdk_root>/<api_dir> 294func nativeLibraryPathFor(lib *nativeLibInfoProperties) string { 295 return filepath.Join(lib.OsPrefix(), lib.archType, 296 nativeStubDir, lib.outputFile.Base()) 297} 298 299// nativeLibInfoProperties represents properties of a native lib 300// 301// The exported (capitalized) fields will be examined and may be changed during common value extraction. 302// The unexported fields will be left untouched. 303type nativeLibInfoProperties struct { 304 android.SdkMemberPropertiesBase 305 306 memberType *librarySdkMemberType 307 308 // The name of the library, is not exported as this must not be changed during optimization. 309 name string 310 311 // archType is not exported as if set (to a non default value) it is always arch specific. 312 // This is "" for common properties. 313 archType string 314 315 // The list of possibly common exported include dirs. 316 // 317 // This field is exported as its contents may not be arch specific. 318 ExportedIncludeDirs android.Paths `android:"arch_variant"` 319 320 // The list of arch specific exported generated include dirs. 321 // 322 // This field is not exported as its contents are always arch specific. 323 exportedGeneratedIncludeDirs android.Paths 324 325 // The list of arch specific exported generated header files. 326 // 327 // This field is not exported as its contents are is always arch specific. 328 exportedGeneratedHeaders android.Paths 329 330 // The list of possibly common exported system include dirs. 331 // 332 // This field is exported as its contents may not be arch specific. 333 ExportedSystemIncludeDirs android.Paths `android:"arch_variant"` 334 335 // The list of possibly common exported flags. 336 // 337 // This field is exported as its contents may not be arch specific. 338 ExportedFlags []string `android:"arch_variant"` 339 340 // The set of shared libraries 341 // 342 // This field is exported as its contents may not be arch specific. 343 SharedLibs []string `android:"arch_variant"` 344 345 // The set of system shared libraries. Note nil and [] are semantically 346 // distinct - see BaseLinkerProperties.System_shared_libs. 347 // 348 // This field is exported as its contents may not be arch specific. 349 SystemSharedLibs []string `android:"arch_variant"` 350 351 // The specific stubs version for the lib variant, or empty string if stubs 352 // are not in use. 353 // 354 // Marked 'ignored-on-host' as the StubsVersion() from which this is initialized is 355 // not set on host and the stubs.versions property which this is written to is does 356 // not vary by arch so cannot be android specific. 357 StubsVersion string `sdk:"ignored-on-host"` 358 359 // outputFile is not exported as it is always arch specific. 360 outputFile android.Path 361} 362 363func (p *nativeLibInfoProperties) PopulateFromVariant(ctx android.SdkMemberContext, variant android.Module) { 364 ccModule := variant.(*Module) 365 366 // If the library has some link types then it produces an output binary file, otherwise it 367 // is header only. 368 if !p.memberType.noOutputFiles { 369 p.outputFile = getRequiredMemberOutputFile(ctx, ccModule) 370 } 371 372 // Separate out the generated include dirs (which are arch specific) from the 373 // include dirs (which may not be). 374 exportedIncludeDirs, exportedGeneratedIncludeDirs := android.FilterPathListPredicate( 375 ccModule.ExportedIncludeDirs(), isGeneratedHeaderDirectory) 376 377 p.name = variant.Name() 378 p.archType = ccModule.Target().Arch.ArchType.String() 379 380 // Make sure that the include directories are unique. 381 p.ExportedIncludeDirs = android.FirstUniquePaths(exportedIncludeDirs) 382 p.exportedGeneratedIncludeDirs = android.FirstUniquePaths(exportedGeneratedIncludeDirs) 383 384 // Take a copy before filtering out duplicates to avoid changing the slice owned by the 385 // ccModule. 386 dirs := append(android.Paths(nil), ccModule.ExportedSystemIncludeDirs()...) 387 p.ExportedSystemIncludeDirs = android.FirstUniquePaths(dirs) 388 389 p.ExportedFlags = ccModule.ExportedFlags() 390 if ccModule.linker != nil { 391 specifiedDeps := specifiedDeps{} 392 specifiedDeps = ccModule.linker.linkerSpecifiedDeps(specifiedDeps) 393 394 if !ccModule.HasStubsVariants() { 395 // Propagate dynamic dependencies for implementation libs, but not stubs. 396 p.SharedLibs = specifiedDeps.sharedLibs 397 } 398 p.SystemSharedLibs = specifiedDeps.systemSharedLibs 399 } 400 p.exportedGeneratedHeaders = ccModule.ExportedGeneratedHeaders() 401 402 if ccModule.HasStubsVariants() { 403 p.StubsVersion = ccModule.StubsVersion() 404 } 405} 406 407func getRequiredMemberOutputFile(ctx android.SdkMemberContext, ccModule *Module) android.Path { 408 var path android.Path 409 outputFile := ccModule.OutputFile() 410 if outputFile.Valid() { 411 path = outputFile.Path() 412 } else { 413 ctx.SdkModuleContext().ModuleErrorf("member variant %s does not have a valid output file", ccModule) 414 } 415 return path 416} 417 418func (p *nativeLibInfoProperties) AddToPropertySet(ctx android.SdkMemberContext, propertySet android.BpPropertySet) { 419 addPossiblyArchSpecificProperties(ctx.SdkModuleContext(), ctx.SnapshotBuilder(), p, propertySet) 420} 421