blob: a36917eda3558ca29e00459e3264301100e7fea0 [file] [log] [blame]
Paul Duffin2f6bc092019-12-13 10:40:56 +00001// 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 "reflect"
20
21 "android/soong/android"
22 "github.com/google/blueprint"
23)
24
25// This file contains support for using cc library modules within an sdk.
26
Paul Duffina0843f62019-12-13 19:50:38 +000027var sharedLibrarySdkMemberType = &librarySdkMemberType{
28 SdkMemberTypeBase: android.SdkMemberTypeBase{
29 PropertyName: "native_shared_libs",
Paul Duffine6029182019-12-16 17:43:48 +000030 SupportsSdk: true,
Paul Duffina0843f62019-12-13 19:50:38 +000031 },
32 prebuiltModuleType: "cc_prebuilt_library_shared",
33 linkTypes: []string{"shared"},
34}
35
36var staticLibrarySdkMemberType = &librarySdkMemberType{
37 SdkMemberTypeBase: android.SdkMemberTypeBase{
38 PropertyName: "native_static_libs",
Paul Duffine6029182019-12-16 17:43:48 +000039 SupportsSdk: true,
Paul Duffina0843f62019-12-13 19:50:38 +000040 },
41 prebuiltModuleType: "cc_prebuilt_library_static",
42 linkTypes: []string{"static"},
43}
44
Paul Duffin255f18e2019-12-13 11:22:16 +000045func init() {
46 // Register sdk member types.
Paul Duffina0843f62019-12-13 19:50:38 +000047 android.RegisterSdkMemberType(sharedLibrarySdkMemberType)
48 android.RegisterSdkMemberType(staticLibrarySdkMemberType)
Paul Duffin2f6bc092019-12-13 10:40:56 +000049}
50
51type librarySdkMemberType struct {
Paul Duffin255f18e2019-12-13 11:22:16 +000052 android.SdkMemberTypeBase
53
Paul Duffin2f6bc092019-12-13 10:40:56 +000054 prebuiltModuleType string
55
56 // The set of link types supported, set of "static", "shared".
57 linkTypes []string
58}
59
60func (mt *librarySdkMemberType) AddDependencies(mctx android.BottomUpMutatorContext, dependencyTag blueprint.DependencyTag, names []string) {
61 targets := mctx.MultiTargets()
62 for _, lib := range names {
63 for _, target := range targets {
64 name, version := StubsLibNameAndVersion(lib)
65 if version == "" {
66 version = LatestStubsVersionFor(mctx.Config(), name)
67 }
Paul Duffin91756d22020-02-21 16:29:57 +000068 if mt.linkTypes == nil {
Paul Duffin2f6bc092019-12-13 10:40:56 +000069 mctx.AddFarVariationDependencies(append(target.Variations(), []blueprint.Variation{
70 {Mutator: "image", Variation: android.CoreVariation},
Paul Duffin2f6bc092019-12-13 10:40:56 +000071 {Mutator: "version", Variation: version},
72 }...), dependencyTag, name)
Paul Duffin91756d22020-02-21 16:29:57 +000073 } else {
74 for _, linkType := range mt.linkTypes {
75 mctx.AddFarVariationDependencies(append(target.Variations(), []blueprint.Variation{
76 {Mutator: "image", Variation: android.CoreVariation},
77 {Mutator: "link", Variation: linkType},
78 {Mutator: "version", Variation: version},
79 }...), dependencyTag, name)
80 }
Paul Duffin2f6bc092019-12-13 10:40:56 +000081 }
82 }
83 }
84}
85
86func (mt *librarySdkMemberType) IsInstance(module android.Module) bool {
Paul Duffina0843f62019-12-13 19:50:38 +000087 // Check the module to see if it can be used with this module type.
88 if m, ok := module.(*Module); ok {
89 for _, allowableMemberType := range m.sdkMemberTypes {
90 if allowableMemberType == mt {
91 return true
92 }
93 }
94 }
95
96 return false
Paul Duffin2f6bc092019-12-13 10:40:56 +000097}
98
99// copy exported header files and stub *.so files
100func (mt *librarySdkMemberType) BuildSnapshot(sdkModuleContext android.ModuleContext, builder android.SnapshotBuilder, member android.SdkMember) {
101 info := mt.organizeVariants(member)
Paul Duffin64f54b02020-02-20 14:33:54 +0000102 info.generatePrebuiltLibrary(sdkModuleContext, builder, member)
Paul Duffin2f6bc092019-12-13 10:40:56 +0000103}
104
105// Organize the variants by architecture.
106func (mt *librarySdkMemberType) organizeVariants(member android.SdkMember) *nativeLibInfo {
107 memberName := member.Name()
108 info := &nativeLibInfo{
109 name: memberName,
110 memberType: mt,
111 }
112
113 for _, variant := range member.Variants() {
114 ccModule := variant.(*Module)
115
116 // Separate out the generated include dirs (which are arch specific) from the
117 // include dirs (which may not be).
118 exportedIncludeDirs, exportedGeneratedIncludeDirs := android.FilterPathListPredicate(
119 ccModule.ExportedIncludeDirs(), isGeneratedHeaderDirectory)
120
121 info.archVariantProperties = append(info.archVariantProperties, nativeLibInfoProperties{
122 name: memberName,
123 archType: ccModule.Target().Arch.ArchType.String(),
124 ExportedIncludeDirs: exportedIncludeDirs,
Paul Duffin5efd1982020-02-20 14:33:54 +0000125 exportedGeneratedIncludeDirs: exportedGeneratedIncludeDirs,
Paul Duffin2f6bc092019-12-13 10:40:56 +0000126 ExportedSystemIncludeDirs: ccModule.ExportedSystemIncludeDirs(),
127 ExportedFlags: ccModule.ExportedFlags(),
128 exportedGeneratedHeaders: ccModule.ExportedGeneratedHeaders(),
129 outputFile: ccModule.OutputFile().Path(),
130 })
131 }
132
133 // Initialize the unexported properties that will not be set during the
134 // extraction process.
135 info.commonProperties.name = memberName
136
137 // Extract common properties from the arch specific properties.
138 extractCommonProperties(&info.commonProperties, info.archVariantProperties)
139
140 return info
141}
142
143func isGeneratedHeaderDirectory(p android.Path) bool {
144 _, gen := p.(android.WritablePath)
145 return gen
146}
147
148// Extract common properties from a slice of property structures of the same type.
149//
150// All the property structures must be of the same type.
151// commonProperties - must be a pointer to the structure into which common properties will be added.
152// inputPropertiesSlice - must be a slice of input properties structures.
153//
154// Iterates over each exported field (capitalized name) and checks to see whether they
155// have the same value (using DeepEquals) across all the input properties. If it does not then no
156// change is made. Otherwise, the common value is stored in the field in the commonProperties
157// and the field in each of the input properties structure is set to its default value.
158func extractCommonProperties(commonProperties interface{}, inputPropertiesSlice interface{}) {
159 commonStructValue := reflect.ValueOf(commonProperties).Elem()
160 propertiesStructType := commonStructValue.Type()
161
162 // Create an empty structure from which default values for the field can be copied.
163 emptyStructValue := reflect.New(propertiesStructType).Elem()
164
165 for f := 0; f < propertiesStructType.NumField(); f++ {
166 // Check to see if all the structures have the same value for the field. The commonValue
167 // is nil on entry to the loop and if it is nil on exit then there is no common value,
168 // otherwise it points to the common value.
169 var commonValue *reflect.Value
170 sliceValue := reflect.ValueOf(inputPropertiesSlice)
171
172 for i := 0; i < sliceValue.Len(); i++ {
173 structValue := sliceValue.Index(i)
174 fieldValue := structValue.Field(f)
175 if !fieldValue.CanInterface() {
176 // The field is not exported so ignore it.
177 continue
178 }
179
180 if commonValue == nil {
181 // Use the first value as the commonProperties value.
182 commonValue = &fieldValue
183 } else {
184 // If the value does not match the current common value then there is
185 // no value in common so break out.
186 if !reflect.DeepEqual(fieldValue.Interface(), commonValue.Interface()) {
187 commonValue = nil
188 break
189 }
190 }
191 }
192
193 // If the fields all have a common value then store it in the common struct field
194 // and set the input struct's field to the empty value.
195 if commonValue != nil {
196 emptyValue := emptyStructValue.Field(f)
197 commonStructValue.Field(f).Set(*commonValue)
198 for i := 0; i < sliceValue.Len(); i++ {
199 structValue := sliceValue.Index(i)
200 fieldValue := structValue.Field(f)
201 fieldValue.Set(emptyValue)
202 }
203 }
204 }
205}
206
Paul Duffin2f6bc092019-12-13 10:40:56 +0000207func (info *nativeLibInfo) generatePrebuiltLibrary(sdkModuleContext android.ModuleContext, builder android.SnapshotBuilder, member android.SdkMember) {
208
Paul Duffin2f6bc092019-12-13 10:40:56 +0000209 pbm := builder.AddPrebuiltModule(member, info.memberType.prebuiltModuleType)
210
Paul Duffin64f54b02020-02-20 14:33:54 +0000211 addPossiblyArchSpecificProperties(sdkModuleContext, builder, info.commonProperties, pbm)
Paul Duffin2f6bc092019-12-13 10:40:56 +0000212
213 archProperties := pbm.AddPropertySet("arch")
214 for _, av := range info.archVariantProperties {
215 archTypeProperties := archProperties.AddPropertySet(av.archType)
Paul Duffin2f6bc092019-12-13 10:40:56 +0000216
Paul Duffin91756d22020-02-21 16:29:57 +0000217 // If the library has some link types then it produces an output binary file, otherwise it
218 // is header only.
219 if info.memberType.linkTypes != nil {
220 // Copy the generated library to the snapshot and add a reference to it in the .bp module.
221 nativeLibraryPath := nativeLibraryPathFor(av)
222 builder.CopyToSnapshot(av.outputFile, nativeLibraryPath)
223 archTypeProperties.AddProperty("srcs", []string{nativeLibraryPath})
224 }
Paul Duffin64f54b02020-02-20 14:33:54 +0000225
226 // Add any arch specific properties inside the appropriate arch: {<arch>: {...}} block
227 addPossiblyArchSpecificProperties(sdkModuleContext, builder, av, archTypeProperties)
Paul Duffin2f6bc092019-12-13 10:40:56 +0000228 }
229 pbm.AddProperty("stl", "none")
230 pbm.AddProperty("system_shared_libs", []string{})
231}
232
Paul Duffin64f54b02020-02-20 14:33:54 +0000233type includeDirsProperty struct {
234 // Accessor to retrieve the paths
235 pathsGetter func(libInfo nativeLibInfoProperties) android.Paths
236
237 // The name of the property in the prebuilt library, "" means there is no property.
238 propertyName string
239
240 // The directory within the snapshot directory into which items should be copied.
241 snapshotDir string
242
243 // True if the items on the path should be copied.
244 copy bool
245
246 // True if the paths represent directories, files if they represent files.
247 dirs bool
Paul Duffin74fc1902020-01-23 11:45:03 +0000248}
249
Paul Duffin64f54b02020-02-20 14:33:54 +0000250var includeDirProperties = []includeDirsProperty{
251 {
252 // ExportedIncludeDirs lists directories that contains some header files to be
253 // copied into a directory in the snapshot. The snapshot directories must be added to
254 // the export_include_dirs property in the prebuilt module in the snapshot.
255 pathsGetter: func(libInfo nativeLibInfoProperties) android.Paths { return libInfo.ExportedIncludeDirs },
256 propertyName: "export_include_dirs",
257 snapshotDir: nativeIncludeDir,
258 copy: true,
259 dirs: true,
260 },
261 {
262 // ExportedSystemIncludeDirs lists directories that contains some system header files to
263 // be copied into a directory in the snapshot. The snapshot directories must be added to
264 // the export_system_include_dirs property in the prebuilt module in the snapshot.
265 pathsGetter: func(libInfo nativeLibInfoProperties) android.Paths { return libInfo.ExportedSystemIncludeDirs },
266 propertyName: "export_system_include_dirs",
267 snapshotDir: nativeIncludeDir,
268 copy: true,
269 dirs: true,
270 },
271 {
272 // exportedGeneratedIncludeDirs lists directories that contains some header files
273 // that are explicitly listed in the exportedGeneratedHeaders property. So, the contents
274 // of these directories do not need to be copied, but these directories do need adding to
275 // the export_include_dirs property in the prebuilt module in the snapshot.
276 pathsGetter: func(libInfo nativeLibInfoProperties) android.Paths { return libInfo.exportedGeneratedIncludeDirs },
277 propertyName: "export_include_dirs",
278 snapshotDir: nativeGeneratedIncludeDir,
279 copy: false,
280 dirs: true,
281 },
282 {
283 // exportedGeneratedHeaders lists header files that are in one of the directories
284 // specified in exportedGeneratedIncludeDirs must be copied into the snapshot.
285 // As they are in a directory in exportedGeneratedIncludeDirs they do not need adding to a
286 // property in the prebuilt module in the snapshot.
287 pathsGetter: func(libInfo nativeLibInfoProperties) android.Paths { return libInfo.exportedGeneratedHeaders },
288 propertyName: "",
289 snapshotDir: nativeGeneratedIncludeDir,
290 copy: true,
291 dirs: false,
292 },
293}
294
295// Add properties that may, or may not, be arch specific.
296func addPossiblyArchSpecificProperties(sdkModuleContext android.ModuleContext, builder android.SnapshotBuilder, libInfo nativeLibInfoProperties, outputProperties android.BpPropertySet) {
297
298 // Map from property name to the include dirs to add to the prebuilt module in the snapshot.
299 includeDirs := make(map[string][]string)
300
301 // Iterate over each include directory property, copying files and collating property
302 // values where necessary.
303 for _, propertyInfo := range includeDirProperties {
304 // Calculate the base directory in the snapshot into which the files will be copied.
305 // lib.ArchType is "" for common properties.
306 targetDir := filepath.Join(libInfo.archType, propertyInfo.snapshotDir)
307
308 propertyName := propertyInfo.propertyName
309
310 // Iterate over each path in one of the include directory properties.
311 for _, path := range propertyInfo.pathsGetter(libInfo) {
312
313 // Copy the files/directories when necessary.
314 if propertyInfo.copy {
315 if propertyInfo.dirs {
316 // When copying a directory glob and copy all the headers within it.
317 // TODO(jiyong) copy headers having other suffixes
318 headers, _ := sdkModuleContext.GlobWithDeps(path.String()+"/**/*.h", nil)
319 for _, file := range headers {
320 src := android.PathForSource(sdkModuleContext, file)
321 dest := filepath.Join(targetDir, file)
322 builder.CopyToSnapshot(src, dest)
323 }
324 } else {
325 // Otherwise, just copy the files.
326 dest := filepath.Join(targetDir, libInfo.name, path.Rel())
327 builder.CopyToSnapshot(path, dest)
328 }
329 }
330
331 // Only directories are added to a property.
332 if propertyInfo.dirs {
333 var snapshotPath string
334 if isGeneratedHeaderDirectory(path) {
335 snapshotPath = filepath.Join(targetDir, libInfo.name)
336 } else {
337 snapshotPath = filepath.Join(targetDir, path.String())
338 }
339
340 includeDirs[propertyName] = append(includeDirs[propertyName], snapshotPath)
341 }
342 }
Paul Duffin74fc1902020-01-23 11:45:03 +0000343 }
Paul Duffin64f54b02020-02-20 14:33:54 +0000344
345 // Add the collated include dir properties to the output.
346 for property, dirs := range includeDirs {
347 outputProperties.AddProperty(property, dirs)
Paul Duffin74fc1902020-01-23 11:45:03 +0000348 }
Paul Duffin74fc1902020-01-23 11:45:03 +0000349}
350
Paul Duffin2f6bc092019-12-13 10:40:56 +0000351const (
352 nativeIncludeDir = "include"
353 nativeGeneratedIncludeDir = "include_gen"
354 nativeStubDir = "lib"
355)
356
357// path to the native library. Relative to <sdk_root>/<api_dir>
358func nativeLibraryPathFor(lib nativeLibInfoProperties) string {
359 return filepath.Join(lib.archType,
360 nativeStubDir, lib.outputFile.Base())
361}
362
Paul Duffin2f6bc092019-12-13 10:40:56 +0000363// nativeLibInfoProperties represents properties of a native lib
364//
365// The exported (capitalized) fields will be examined and may be changed during common value extraction.
366// The unexported fields will be left untouched.
367type nativeLibInfoProperties struct {
368 // The name of the library, is not exported as this must not be changed during optimization.
369 name string
370
371 // archType is not exported as if set (to a non default value) it is always arch specific.
372 // This is "" for common properties.
373 archType string
374
Paul Duffin5efd1982020-02-20 14:33:54 +0000375 // The list of possibly common exported include dirs.
376 //
377 // This field is exported as its contents may not be arch specific.
378 ExportedIncludeDirs android.Paths
Paul Duffin2f6bc092019-12-13 10:40:56 +0000379
Paul Duffin5efd1982020-02-20 14:33:54 +0000380 // The list of arch specific exported generated include dirs.
381 //
382 // This field is not exported as its contents are always arch specific.
383 exportedGeneratedIncludeDirs android.Paths
384
385 // The list of arch specific exported generated header files.
386 //
387 // This field is not exported as its contents are is always arch specific.
Paul Duffin2f6bc092019-12-13 10:40:56 +0000388 exportedGeneratedHeaders android.Paths
389
Paul Duffin5efd1982020-02-20 14:33:54 +0000390 // The list of possibly common exported system include dirs.
391 //
392 // This field is exported as its contents may not be arch specific.
393 ExportedSystemIncludeDirs android.Paths
394
395 // The list of possibly common exported flags.
396 //
397 // This field is exported as its contents may not be arch specific.
398 ExportedFlags []string
399
Paul Duffin2f6bc092019-12-13 10:40:56 +0000400 // outputFile is not exported as it is always arch specific.
401 outputFile android.Path
402}
403
404// nativeLibInfo represents a collection of arch-specific modules having the same name
405type nativeLibInfo struct {
406 name string
407 memberType *librarySdkMemberType
408 archVariantProperties []nativeLibInfoProperties
409 commonProperties nativeLibInfoProperties
410}