• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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