1// Copyright 2021 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 "regexp" 19 "strings" 20 21 "android/soong/android" 22 "android/soong/multitree" 23 24 "github.com/google/blueprint/proptools" 25) 26 27var ( 28 ndkVariantRegex = regexp.MustCompile("ndk\\.([a-zA-Z0-9]+)") 29 stubVariantRegex = regexp.MustCompile("apex\\.([a-zA-Z0-9]+)") 30) 31 32func init() { 33 RegisterLibraryStubBuildComponents(android.InitRegistrationContext) 34} 35 36func RegisterLibraryStubBuildComponents(ctx android.RegistrationContext) { 37 ctx.RegisterModuleType("cc_api_library", CcApiLibraryFactory) 38 ctx.RegisterModuleType("cc_api_headers", CcApiHeadersFactory) 39 ctx.RegisterModuleType("cc_api_variant", CcApiVariantFactory) 40} 41 42func updateImportedLibraryDependency(ctx android.BottomUpMutatorContext) { 43 m, ok := ctx.Module().(*Module) 44 if !ok { 45 return 46 } 47 48 apiLibrary, ok := m.linker.(*apiLibraryDecorator) 49 if !ok { 50 return 51 } 52 53 if m.InVendorOrProduct() && apiLibrary.hasLLNDKStubs() { 54 // Add LLNDK variant dependency 55 if inList("llndk", apiLibrary.properties.Variants) { 56 variantName := BuildApiVariantName(m.BaseModuleName(), "llndk", "") 57 ctx.AddDependency(m, nil, variantName) 58 } 59 } else if m.IsSdkVariant() { 60 // Add NDK variant dependencies 61 targetVariant := "ndk." + m.StubsVersion() 62 if inList(targetVariant, apiLibrary.properties.Variants) { 63 variantName := BuildApiVariantName(m.BaseModuleName(), targetVariant, "") 64 ctx.AddDependency(m, nil, variantName) 65 } 66 } else if m.IsStubs() { 67 targetVariant := "apex." + m.StubsVersion() 68 if inList(targetVariant, apiLibrary.properties.Variants) { 69 variantName := BuildApiVariantName(m.BaseModuleName(), targetVariant, "") 70 ctx.AddDependency(m, nil, variantName) 71 } 72 } 73} 74 75// 'cc_api_library' is a module type which is from the exported API surface 76// with C shared library type. The module will replace original module, and 77// offer a link to the module that generates shared library object from the 78// map file. 79type apiLibraryProperties struct { 80 Src *string `android:"arch_variant"` 81 Variants []string 82} 83 84type apiLibraryDecorator struct { 85 *libraryDecorator 86 properties apiLibraryProperties 87} 88 89func CcApiLibraryFactory() android.Module { 90 module, decorator := NewLibrary(android.DeviceSupported) 91 apiLibraryDecorator := &apiLibraryDecorator{ 92 libraryDecorator: decorator, 93 } 94 apiLibraryDecorator.BuildOnlyShared() 95 96 module.stl = nil 97 module.sanitize = nil 98 decorator.disableStripping() 99 100 module.compiler = nil 101 module.linker = apiLibraryDecorator 102 module.installer = nil 103 module.library = apiLibraryDecorator 104 module.AddProperties(&module.Properties, &apiLibraryDecorator.properties) 105 106 // Prevent default system libs (libc, libm, and libdl) from being linked 107 if apiLibraryDecorator.baseLinker.Properties.System_shared_libs == nil { 108 apiLibraryDecorator.baseLinker.Properties.System_shared_libs = []string{} 109 } 110 111 apiLibraryDecorator.baseLinker.Properties.No_libcrt = BoolPtr(true) 112 apiLibraryDecorator.baseLinker.Properties.Nocrt = BoolPtr(true) 113 114 module.Init() 115 116 return module 117} 118 119func (d *apiLibraryDecorator) Name(basename string) string { 120 return basename + multitree.GetApiImportSuffix() 121} 122 123// Export include dirs without checking for existence. 124// The directories are not guaranteed to exist during Soong analysis. 125func (d *apiLibraryDecorator) exportIncludes(ctx ModuleContext) { 126 exporterProps := d.flagExporter.Properties 127 for _, dir := range exporterProps.Export_include_dirs.GetOrDefault(ctx, nil) { 128 d.dirs = append(d.dirs, android.MaybeExistentPathForSource(ctx, ctx.ModuleDir(), dir)) 129 } 130 // system headers 131 for _, dir := range exporterProps.Export_system_include_dirs { 132 d.systemDirs = append(d.systemDirs, android.MaybeExistentPathForSource(ctx, ctx.ModuleDir(), dir)) 133 } 134} 135 136func (d *apiLibraryDecorator) linkerInit(ctx BaseModuleContext) { 137 d.baseLinker.linkerInit(ctx) 138 139 if d.hasNDKStubs() { 140 // Set SDK version of module as current 141 ctx.Module().(*Module).Properties.Sdk_version = StringPtr("current") 142 143 // Add NDK stub as NDK known libs 144 name := ctx.ModuleName() 145 146 ndkKnownLibsLock.Lock() 147 ndkKnownLibs := getNDKKnownLibs(ctx.Config()) 148 if !inList(name, *ndkKnownLibs) { 149 *ndkKnownLibs = append(*ndkKnownLibs, name) 150 } 151 ndkKnownLibsLock.Unlock() 152 } 153} 154 155func (d *apiLibraryDecorator) link(ctx ModuleContext, flags Flags, deps PathDeps, objects Objects) android.Path { 156 m, _ := ctx.Module().(*Module) 157 158 var in android.Path 159 160 // src might not exist during the beginning of soong analysis in Multi-tree 161 if src := String(d.properties.Src); src != "" { 162 in = android.MaybeExistentPathForSource(ctx, ctx.ModuleDir(), src) 163 } 164 165 libName := m.BaseModuleName() + multitree.GetApiImportSuffix() 166 167 load_cc_variant := func(apiVariantModule string) { 168 var mod android.Module 169 170 ctx.VisitDirectDeps(func(depMod android.Module) { 171 if depMod.Name() == apiVariantModule { 172 mod = depMod 173 libName = apiVariantModule 174 } 175 }) 176 177 if mod != nil { 178 variantMod, ok := mod.(*CcApiVariant) 179 if ok { 180 in = variantMod.Src() 181 182 // Copy LLDNK properties to cc_api_library module 183 exportIncludeDirs := append(d.libraryDecorator.flagExporter.Properties.Export_include_dirs.GetOrDefault(ctx, nil), 184 variantMod.exportProperties.Export_include_dirs...) 185 d.libraryDecorator.flagExporter.Properties.Export_include_dirs = proptools.NewConfigurable[[]string]( 186 nil, 187 []proptools.ConfigurableCase[[]string]{ 188 proptools.NewConfigurableCase[[]string](nil, &exportIncludeDirs), 189 }, 190 ) 191 192 // Export headers as system include dirs if specified. Mostly for libc 193 if Bool(variantMod.exportProperties.Export_headers_as_system) { 194 d.libraryDecorator.flagExporter.Properties.Export_system_include_dirs = append( 195 d.libraryDecorator.flagExporter.Properties.Export_system_include_dirs, 196 d.libraryDecorator.flagExporter.Properties.Export_include_dirs.GetOrDefault(ctx, nil)...) 197 d.libraryDecorator.flagExporter.Properties.Export_include_dirs = proptools.NewConfigurable[[]string](nil, nil) 198 } 199 } 200 } 201 } 202 203 if m.InVendorOrProduct() && d.hasLLNDKStubs() { 204 // LLNDK variant 205 load_cc_variant(BuildApiVariantName(m.BaseModuleName(), "llndk", "")) 206 } else if m.IsSdkVariant() { 207 // NDK Variant 208 load_cc_variant(BuildApiVariantName(m.BaseModuleName(), "ndk", m.StubsVersion())) 209 } else if m.IsStubs() { 210 // APEX Variant 211 load_cc_variant(BuildApiVariantName(m.BaseModuleName(), "apex", m.StubsVersion())) 212 } 213 214 // Flags reexported from dependencies. (e.g. vndk_prebuilt_shared) 215 d.exportIncludes(ctx) 216 d.libraryDecorator.reexportDirs(deps.ReexportedDirs...) 217 d.libraryDecorator.reexportSystemDirs(deps.ReexportedSystemDirs...) 218 d.libraryDecorator.reexportFlags(deps.ReexportedFlags...) 219 d.libraryDecorator.reexportDeps(deps.ReexportedDeps...) 220 d.libraryDecorator.addExportedGeneratedHeaders(deps.ReexportedGeneratedHeaders...) 221 222 if in == nil { 223 ctx.PropertyErrorf("src", "Unable to locate source property") 224 return nil 225 } 226 227 // Make the _compilation_ of rdeps have an order-only dep on cc_api_library.src (an .so file) 228 // The .so file itself has an order-only dependency on the headers contributed by this library. 229 // Creating this dependency ensures that the headers are assembled before compilation of rdeps begins. 230 d.libraryDecorator.reexportDeps(in) 231 d.libraryDecorator.flagExporter.setProvider(ctx) 232 233 d.unstrippedOutputFile = in 234 libName += flags.Toolchain.ShlibSuffix() 235 236 tocFile := android.PathForModuleOut(ctx, libName+".toc") 237 d.tocFile = android.OptionalPathForPath(tocFile) 238 TransformSharedObjectToToc(ctx, in, tocFile) 239 240 outputFile := android.PathForModuleOut(ctx, libName) 241 242 // TODO(b/270485584) This copies with a new name, just to avoid conflict with prebuilts. 243 // We can just use original input if there is any way to avoid name conflict without copy. 244 ctx.Build(pctx, android.BuildParams{ 245 Rule: android.Cp, 246 Description: "API surface imported library", 247 Input: in, 248 Output: outputFile, 249 Args: map[string]string{ 250 "cpFlags": "-L", 251 }, 252 }) 253 254 android.SetProvider(ctx, SharedLibraryInfoProvider, SharedLibraryInfo{ 255 SharedLibrary: outputFile, 256 Target: ctx.Target(), 257 258 TableOfContents: d.tocFile, 259 }) 260 261 d.shareStubs(ctx) 262 263 return outputFile 264} 265 266// Share additional information about stub libraries with provider 267func (d *apiLibraryDecorator) shareStubs(ctx ModuleContext) { 268 stubs := ctx.GetDirectDepsWithTag(stubImplDepTag) 269 if len(stubs) > 0 { 270 var stubsInfo []SharedStubLibrary 271 for _, stub := range stubs { 272 stubInfo, _ := android.OtherModuleProvider(ctx, stub, SharedLibraryInfoProvider) 273 flagInfo, _ := android.OtherModuleProvider(ctx, stub, FlagExporterInfoProvider) 274 stubsInfo = append(stubsInfo, SharedStubLibrary{ 275 Version: moduleLibraryInterface(stub).stubsVersion(), 276 SharedLibraryInfo: stubInfo, 277 FlagExporterInfo: flagInfo, 278 }) 279 } 280 android.SetProvider(ctx, SharedLibraryStubsProvider, SharedLibraryStubsInfo{ 281 SharedStubLibraries: stubsInfo, 282 283 IsLLNDK: ctx.IsLlndk(), 284 }) 285 } 286} 287 288func (d *apiLibraryDecorator) availableFor(what string) bool { 289 // Stub from API surface should be available for any APEX. 290 return true 291} 292 293func (d *apiLibraryDecorator) hasApexStubs() bool { 294 for _, variant := range d.properties.Variants { 295 if strings.HasPrefix(variant, "apex") { 296 return true 297 } 298 } 299 return false 300} 301 302func (d *apiLibraryDecorator) hasStubsVariants() bool { 303 return d.hasApexStubs() 304} 305 306func (d *apiLibraryDecorator) stubsVersions(ctx android.BaseMutatorContext) []string { 307 m, ok := ctx.Module().(*Module) 308 309 if !ok { 310 return nil 311 } 312 313 // TODO(b/244244438) Create more version information for NDK and APEX variations 314 // NDK variants 315 if m.IsSdkVariant() { 316 // TODO(b/249193999) Do not check if module has NDK stubs once all NDK cc_api_library contains ndk variant of cc_api_variant. 317 if d.hasNDKStubs() { 318 return d.getNdkVersions() 319 } 320 } 321 322 if d.hasLLNDKStubs() && m.InVendorOrProduct() { 323 // LLNDK libraries only need a single stubs variant. 324 return []string{android.FutureApiLevel.String()} 325 } 326 327 stubsVersions := d.getStubVersions() 328 329 if len(stubsVersions) != 0 { 330 return stubsVersions 331 } 332 333 if m.MinSdkVersion() == "" { 334 return nil 335 } 336 337 firstVersion, err := nativeApiLevelFromUser(ctx, 338 m.MinSdkVersion()) 339 340 if err != nil { 341 return nil 342 } 343 344 return ndkLibraryVersions(ctx, firstVersion) 345} 346 347func (d *apiLibraryDecorator) hasLLNDKStubs() bool { 348 return inList("llndk", d.properties.Variants) 349} 350 351func (d *apiLibraryDecorator) hasNDKStubs() bool { 352 for _, variant := range d.properties.Variants { 353 if ndkVariantRegex.MatchString(variant) { 354 return true 355 } 356 } 357 return false 358} 359 360func (d *apiLibraryDecorator) getNdkVersions() []string { 361 ndkVersions := []string{} 362 363 for _, variant := range d.properties.Variants { 364 if match := ndkVariantRegex.FindStringSubmatch(variant); len(match) == 2 { 365 ndkVersions = append(ndkVersions, match[1]) 366 } 367 } 368 369 return ndkVersions 370} 371 372func (d *apiLibraryDecorator) getStubVersions() []string { 373 stubVersions := []string{} 374 375 for _, variant := range d.properties.Variants { 376 if match := stubVariantRegex.FindStringSubmatch(variant); len(match) == 2 { 377 stubVersions = append(stubVersions, match[1]) 378 } 379 } 380 381 return stubVersions 382} 383 384// 'cc_api_headers' is similar with 'cc_api_library', but which replaces 385// header libraries. The module will replace any dependencies to existing 386// original header libraries. 387type apiHeadersDecorator struct { 388 *libraryDecorator 389} 390 391func CcApiHeadersFactory() android.Module { 392 module, decorator := NewLibrary(android.DeviceSupported) 393 apiHeadersDecorator := &apiHeadersDecorator{ 394 libraryDecorator: decorator, 395 } 396 apiHeadersDecorator.HeaderOnly() 397 398 module.stl = nil 399 module.sanitize = nil 400 decorator.disableStripping() 401 402 module.compiler = nil 403 module.linker = apiHeadersDecorator 404 module.installer = nil 405 406 // Prevent default system libs (libc, libm, and libdl) from being linked 407 if apiHeadersDecorator.baseLinker.Properties.System_shared_libs == nil { 408 apiHeadersDecorator.baseLinker.Properties.System_shared_libs = []string{} 409 } 410 411 apiHeadersDecorator.baseLinker.Properties.No_libcrt = BoolPtr(true) 412 apiHeadersDecorator.baseLinker.Properties.Nocrt = BoolPtr(true) 413 414 module.Init() 415 416 return module 417} 418 419func (d *apiHeadersDecorator) Name(basename string) string { 420 return basename + multitree.GetApiImportSuffix() 421} 422 423func (d *apiHeadersDecorator) availableFor(what string) bool { 424 // Stub from API surface should be available for any APEX. 425 return true 426} 427 428type ccApiexportProperties struct { 429 Src *string `android:"arch_variant"` 430 Variant *string 431 Version *string 432} 433 434type variantExporterProperties struct { 435 // Header directory to export 436 Export_include_dirs []string `android:"arch_variant"` 437 438 // Export all headers as system include 439 Export_headers_as_system *bool 440} 441 442type CcApiVariant struct { 443 android.ModuleBase 444 445 properties ccApiexportProperties 446 exportProperties variantExporterProperties 447 448 src android.Path 449} 450 451var _ android.Module = (*CcApiVariant)(nil) 452var _ android.ImageInterface = (*CcApiVariant)(nil) 453 454func CcApiVariantFactory() android.Module { 455 module := &CcApiVariant{} 456 457 module.AddProperties(&module.properties) 458 module.AddProperties(&module.exportProperties) 459 460 android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibBoth) 461 return module 462} 463 464func (v *CcApiVariant) GenerateAndroidBuildActions(ctx android.ModuleContext) { 465 // No need to build 466 467 if String(v.properties.Src) == "" { 468 ctx.PropertyErrorf("src", "src is a required property") 469 } 470 471 // Skip the existence check of the stub prebuilt file. 472 // The file is not guaranteed to exist during Soong analysis. 473 // Build orchestrator will be responsible for creating a connected ninja graph. 474 v.src = android.MaybeExistentPathForSource(ctx, ctx.ModuleDir(), String(v.properties.Src)) 475} 476 477func (v *CcApiVariant) Name() string { 478 version := String(v.properties.Version) 479 return BuildApiVariantName(v.BaseModuleName(), *v.properties.Variant, version) 480} 481 482func (v *CcApiVariant) Src() android.Path { 483 return v.src 484} 485 486func BuildApiVariantName(baseName string, variant string, version string) string { 487 names := []string{baseName, variant} 488 if version != "" { 489 names = append(names, version) 490 } 491 492 return strings.Join(names[:], ".") + multitree.GetApiImportSuffix() 493} 494 495// Implement ImageInterface to generate image variants 496func (v *CcApiVariant) ImageMutatorBegin(ctx android.BaseModuleContext) {} 497func (v *CcApiVariant) CoreVariantNeeded(ctx android.BaseModuleContext) bool { 498 return inList(String(v.properties.Variant), []string{"ndk", "apex"}) 499} 500func (v *CcApiVariant) RamdiskVariantNeeded(ctx android.BaseModuleContext) bool { return false } 501func (v *CcApiVariant) VendorRamdiskVariantNeeded(ctx android.BaseModuleContext) bool { return false } 502func (v *CcApiVariant) DebugRamdiskVariantNeeded(ctx android.BaseModuleContext) bool { return false } 503func (v *CcApiVariant) RecoveryVariantNeeded(ctx android.BaseModuleContext) bool { return false } 504func (v *CcApiVariant) ExtraImageVariations(ctx android.BaseModuleContext) []string { 505 var variations []string 506 507 if String(v.properties.Variant) == "llndk" { 508 variations = append(variations, VendorVariation) 509 variations = append(variations, ProductVariation) 510 } 511 512 return variations 513} 514func (v *CcApiVariant) SetImageVariation(ctx android.BaseModuleContext, variation string) { 515} 516