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