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 return pbm 128} 129 130func (mt *librarySdkMemberType) CreateVariantPropertiesStruct() android.SdkMemberProperties { 131 return &nativeLibInfoProperties{memberType: mt} 132} 133 134func isGeneratedHeaderDirectory(p android.Path) bool { 135 _, gen := p.(android.WritablePath) 136 return gen 137} 138 139type includeDirsProperty struct { 140 // Accessor to retrieve the paths 141 pathsGetter func(libInfo *nativeLibInfoProperties) android.Paths 142 143 // The name of the property in the prebuilt library, "" means there is no property. 144 propertyName string 145 146 // The directory within the snapshot directory into which items should be copied. 147 snapshotDir string 148 149 // True if the items on the path should be copied. 150 copy bool 151 152 // True if the paths represent directories, files if they represent files. 153 dirs bool 154} 155 156var includeDirProperties = []includeDirsProperty{ 157 { 158 // ExportedIncludeDirs lists directories that contains some header files to be 159 // copied into a directory in the snapshot. The snapshot directories must be added to 160 // the export_include_dirs property in the prebuilt module in the snapshot. 161 pathsGetter: func(libInfo *nativeLibInfoProperties) android.Paths { return libInfo.ExportedIncludeDirs }, 162 propertyName: "export_include_dirs", 163 snapshotDir: nativeIncludeDir, 164 copy: true, 165 dirs: true, 166 }, 167 { 168 // ExportedSystemIncludeDirs lists directories that contains some system header files to 169 // be copied into a directory in the snapshot. The snapshot directories must be added to 170 // the export_system_include_dirs property in the prebuilt module in the snapshot. 171 pathsGetter: func(libInfo *nativeLibInfoProperties) android.Paths { return libInfo.ExportedSystemIncludeDirs }, 172 propertyName: "export_system_include_dirs", 173 snapshotDir: nativeIncludeDir, 174 copy: true, 175 dirs: true, 176 }, 177 { 178 // exportedGeneratedIncludeDirs lists directories that contains some header files 179 // that are explicitly listed in the exportedGeneratedHeaders property. So, the contents 180 // of these directories do not need to be copied, but these directories do need adding to 181 // the export_include_dirs property in the prebuilt module in the snapshot. 182 pathsGetter: func(libInfo *nativeLibInfoProperties) android.Paths { return libInfo.exportedGeneratedIncludeDirs }, 183 propertyName: "export_include_dirs", 184 snapshotDir: nativeGeneratedIncludeDir, 185 copy: false, 186 dirs: true, 187 }, 188 { 189 // exportedGeneratedHeaders lists header files that are in one of the directories 190 // specified in exportedGeneratedIncludeDirs must be copied into the snapshot. 191 // As they are in a directory in exportedGeneratedIncludeDirs they do not need adding to a 192 // property in the prebuilt module in the snapshot. 193 pathsGetter: func(libInfo *nativeLibInfoProperties) android.Paths { return libInfo.exportedGeneratedHeaders }, 194 propertyName: "", 195 snapshotDir: nativeGeneratedIncludeDir, 196 copy: true, 197 dirs: false, 198 }, 199} 200 201// Add properties that may, or may not, be arch specific. 202func addPossiblyArchSpecificProperties(sdkModuleContext android.ModuleContext, builder android.SnapshotBuilder, libInfo *nativeLibInfoProperties, outputProperties android.BpPropertySet) { 203 204 // Copy the generated library to the snapshot and add a reference to it in the .bp module. 205 if libInfo.outputFile != nil { 206 nativeLibraryPath := nativeLibraryPathFor(libInfo) 207 builder.CopyToSnapshot(libInfo.outputFile, nativeLibraryPath) 208 outputProperties.AddProperty("srcs", []string{nativeLibraryPath}) 209 } 210 211 if len(libInfo.SharedLibs) > 0 { 212 outputProperties.AddPropertyWithTag("shared_libs", libInfo.SharedLibs, builder.SdkMemberReferencePropertyTag(false)) 213 } 214 215 // SystemSharedLibs needs to be propagated if it's a list, even if it's empty, 216 // so check for non-nil instead of nonzero length. 217 if libInfo.SystemSharedLibs != nil { 218 outputProperties.AddPropertyWithTag("system_shared_libs", libInfo.SystemSharedLibs, builder.SdkMemberReferencePropertyTag(false)) 219 } 220 221 // Map from property name to the include dirs to add to the prebuilt module in the snapshot. 222 includeDirs := make(map[string][]string) 223 224 // Iterate over each include directory property, copying files and collating property 225 // values where necessary. 226 for _, propertyInfo := range includeDirProperties { 227 // Calculate the base directory in the snapshot into which the files will be copied. 228 // lib.ArchType is "" for common properties. 229 targetDir := filepath.Join(libInfo.archType, propertyInfo.snapshotDir) 230 231 propertyName := propertyInfo.propertyName 232 233 // Iterate over each path in one of the include directory properties. 234 for _, path := range propertyInfo.pathsGetter(libInfo) { 235 236 // Copy the files/directories when necessary. 237 if propertyInfo.copy { 238 if propertyInfo.dirs { 239 // When copying a directory glob and copy all the headers within it. 240 // TODO(jiyong) copy headers having other suffixes 241 headers, _ := sdkModuleContext.GlobWithDeps(path.String()+"/**/*.h", nil) 242 for _, file := range headers { 243 src := android.PathForSource(sdkModuleContext, file) 244 dest := filepath.Join(targetDir, file) 245 builder.CopyToSnapshot(src, dest) 246 } 247 } else { 248 // Otherwise, just copy the files. 249 dest := filepath.Join(targetDir, libInfo.name, path.Rel()) 250 builder.CopyToSnapshot(path, dest) 251 } 252 } 253 254 // Only directories are added to a property. 255 if propertyInfo.dirs { 256 var snapshotPath string 257 if isGeneratedHeaderDirectory(path) { 258 snapshotPath = filepath.Join(targetDir, libInfo.name) 259 } else { 260 snapshotPath = filepath.Join(targetDir, path.String()) 261 } 262 263 includeDirs[propertyName] = append(includeDirs[propertyName], snapshotPath) 264 } 265 } 266 } 267 268 // Add the collated include dir properties to the output. 269 for property, dirs := range includeDirs { 270 outputProperties.AddProperty(property, dirs) 271 } 272 273 if len(libInfo.StubsVersion) > 0 { 274 stubsSet := outputProperties.AddPropertySet("stubs") 275 stubsSet.AddProperty("versions", []string{libInfo.StubsVersion}) 276 } 277} 278 279const ( 280 nativeIncludeDir = "include" 281 nativeGeneratedIncludeDir = "include_gen" 282 nativeStubDir = "lib" 283) 284 285// path to the native library. Relative to <sdk_root>/<api_dir> 286func nativeLibraryPathFor(lib *nativeLibInfoProperties) string { 287 return filepath.Join(lib.OsPrefix(), lib.archType, 288 nativeStubDir, lib.outputFile.Base()) 289} 290 291// nativeLibInfoProperties represents properties of a native lib 292// 293// The exported (capitalized) fields will be examined and may be changed during common value extraction. 294// The unexported fields will be left untouched. 295type nativeLibInfoProperties struct { 296 android.SdkMemberPropertiesBase 297 298 memberType *librarySdkMemberType 299 300 // The name of the library, is not exported as this must not be changed during optimization. 301 name string 302 303 // archType is not exported as if set (to a non default value) it is always arch specific. 304 // This is "" for common properties. 305 archType string 306 307 // The list of possibly common exported include dirs. 308 // 309 // This field is exported as its contents may not be arch specific. 310 ExportedIncludeDirs android.Paths `android:"arch_variant"` 311 312 // The list of arch specific exported generated include dirs. 313 // 314 // This field is not exported as its contents are always arch specific. 315 exportedGeneratedIncludeDirs android.Paths 316 317 // The list of arch specific exported generated header files. 318 // 319 // This field is not exported as its contents are is always arch specific. 320 exportedGeneratedHeaders android.Paths 321 322 // The list of possibly common exported system include dirs. 323 // 324 // This field is exported as its contents may not be arch specific. 325 ExportedSystemIncludeDirs android.Paths `android:"arch_variant"` 326 327 // The list of possibly common exported flags. 328 // 329 // This field is exported as its contents may not be arch specific. 330 ExportedFlags []string `android:"arch_variant"` 331 332 // The set of shared libraries 333 // 334 // This field is exported as its contents may not be arch specific. 335 SharedLibs []string `android:"arch_variant"` 336 337 // The set of system shared libraries. Note nil and [] are semantically 338 // distinct - see BaseLinkerProperties.System_shared_libs. 339 // 340 // This field is exported as its contents may not be arch specific. 341 SystemSharedLibs []string `android:"arch_variant"` 342 343 // The specific stubs version for the lib variant, or empty string if stubs 344 // are not in use. 345 // 346 // Marked 'ignored-on-host' as the StubsVersion() from which this is initialized is 347 // not set on host and the stubs.versions property which this is written to is does 348 // not vary by arch so cannot be android specific. 349 StubsVersion string `sdk:"ignored-on-host"` 350 351 // outputFile is not exported as it is always arch specific. 352 outputFile android.Path 353} 354 355func (p *nativeLibInfoProperties) PopulateFromVariant(ctx android.SdkMemberContext, variant android.Module) { 356 ccModule := variant.(*Module) 357 358 // If the library has some link types then it produces an output binary file, otherwise it 359 // is header only. 360 if !p.memberType.noOutputFiles { 361 p.outputFile = getRequiredMemberOutputFile(ctx, ccModule) 362 } 363 364 // Separate out the generated include dirs (which are arch specific) from the 365 // include dirs (which may not be). 366 exportedIncludeDirs, exportedGeneratedIncludeDirs := android.FilterPathListPredicate( 367 ccModule.ExportedIncludeDirs(), isGeneratedHeaderDirectory) 368 369 p.name = variant.Name() 370 p.archType = ccModule.Target().Arch.ArchType.String() 371 372 // Make sure that the include directories are unique. 373 p.ExportedIncludeDirs = android.FirstUniquePaths(exportedIncludeDirs) 374 p.exportedGeneratedIncludeDirs = android.FirstUniquePaths(exportedGeneratedIncludeDirs) 375 p.ExportedSystemIncludeDirs = android.FirstUniquePaths(ccModule.ExportedSystemIncludeDirs()) 376 377 p.ExportedFlags = ccModule.ExportedFlags() 378 if ccModule.linker != nil { 379 specifiedDeps := specifiedDeps{} 380 specifiedDeps = ccModule.linker.linkerSpecifiedDeps(specifiedDeps) 381 382 if !ccModule.HasStubsVariants() { 383 // Propagate dynamic dependencies for implementation libs, but not stubs. 384 p.SharedLibs = specifiedDeps.sharedLibs 385 } 386 p.SystemSharedLibs = specifiedDeps.systemSharedLibs 387 } 388 p.exportedGeneratedHeaders = ccModule.ExportedGeneratedHeaders() 389 390 if ccModule.HasStubsVariants() { 391 p.StubsVersion = ccModule.StubsVersion() 392 } 393} 394 395func getRequiredMemberOutputFile(ctx android.SdkMemberContext, ccModule *Module) android.Path { 396 var path android.Path 397 outputFile := ccModule.OutputFile() 398 if outputFile.Valid() { 399 path = outputFile.Path() 400 } else { 401 ctx.SdkModuleContext().ModuleErrorf("member variant %s does not have a valid output file", ccModule) 402 } 403 return path 404} 405 406func (p *nativeLibInfoProperties) AddToPropertySet(ctx android.SdkMemberContext, propertySet android.BpPropertySet) { 407 addPossiblyArchSpecificProperties(ctx.SdkModuleContext(), ctx.SnapshotBuilder(), p, propertySet) 408} 409