blob: 171bb3f8c2a158ca9f1cb0e66f5b2f96f4781d5b [file] [log] [blame]
Jiyong Park9b409bc2019-10-11 14:59:13 +09001// Copyright (C) 2019 The Android Open Source Project
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 sdk
16
17import (
18 "fmt"
Jiyong Park9b409bc2019-10-11 14:59:13 +090019 "path/filepath"
Jiyong Park9b409bc2019-10-11 14:59:13 +090020 "strings"
21
22 "github.com/google/blueprint/proptools"
23
24 "android/soong/android"
Jiyong Park73c54ee2019-10-22 20:31:18 +090025 "android/soong/cc"
Jiyong Park9b409bc2019-10-11 14:59:13 +090026 "android/soong/java"
27)
28
29var pctx = android.NewPackageContext("android/soong/sdk")
30
31// generatedFile abstracts operations for writing contents into a file and emit a build rule
32// for the file.
33type generatedFile struct {
Jiyong Park73c54ee2019-10-22 20:31:18 +090034 path android.OutputPath
35 content strings.Builder
36 indentLevel int
Jiyong Park9b409bc2019-10-11 14:59:13 +090037}
38
Jiyong Park232e7852019-11-04 12:23:40 +090039func newGeneratedFile(ctx android.ModuleContext, path ...string) *generatedFile {
Jiyong Park9b409bc2019-10-11 14:59:13 +090040 return &generatedFile{
Jiyong Park232e7852019-11-04 12:23:40 +090041 path: android.PathForModuleOut(ctx, path...).OutputPath,
Jiyong Park73c54ee2019-10-22 20:31:18 +090042 indentLevel: 0,
Jiyong Park9b409bc2019-10-11 14:59:13 +090043 }
44}
45
Jiyong Park73c54ee2019-10-22 20:31:18 +090046func (gf *generatedFile) indent() {
47 gf.indentLevel++
48}
49
50func (gf *generatedFile) dedent() {
51 gf.indentLevel--
52}
53
Jiyong Park9b409bc2019-10-11 14:59:13 +090054func (gf *generatedFile) printfln(format string, args ...interface{}) {
55 // ninja consumes newline characters in rspfile_content. Prevent it by
56 // escaping the backslash in the newline character. The extra backshash
57 // is removed when the rspfile is written to the actual script file
Jiyong Park73c54ee2019-10-22 20:31:18 +090058 fmt.Fprintf(&(gf.content), strings.Repeat(" ", gf.indentLevel)+format+"\\n", args...)
Jiyong Park9b409bc2019-10-11 14:59:13 +090059}
60
61func (gf *generatedFile) build(pctx android.PackageContext, ctx android.BuilderContext, implicits android.Paths) {
62 rb := android.NewRuleBuilder()
63 // convert \\n to \n
64 rb.Command().
65 Implicits(implicits).
66 Text("echo").Text(proptools.ShellEscape(gf.content.String())).
67 Text("| sed 's/\\\\n/\\n/g' >").Output(gf.path)
68 rb.Command().
69 Text("chmod a+x").Output(gf.path)
70 rb.Build(pctx, ctx, gf.path.Base(), "Build "+gf.path.Base())
71}
72
Jiyong Park73c54ee2019-10-22 20:31:18 +090073func (s *sdk) javaLibs(ctx android.ModuleContext) []*java.Library {
74 result := []*java.Library{}
Jiyong Park9b409bc2019-10-11 14:59:13 +090075 ctx.VisitDirectDeps(func(m android.Module) {
Jiyong Park73c54ee2019-10-22 20:31:18 +090076 if j, ok := m.(*java.Library); ok {
77 result = append(result, j)
Jiyong Park9b409bc2019-10-11 14:59:13 +090078 }
79 })
80 return result
81}
82
Jiyong Park73c54ee2019-10-22 20:31:18 +090083// archSpecificNativeLibInfo represents an arch-specific variant of a native lib
84type archSpecificNativeLibInfo struct {
85 name string
86 archType string
87 exportedIncludeDirs android.Paths
88 exportedSystemIncludeDirs android.Paths
89 exportedFlags []string
Jiyong Park232e7852019-11-04 12:23:40 +090090 exportedDeps android.Paths
Jiyong Park73c54ee2019-10-22 20:31:18 +090091 outputFile android.Path
92}
Jiyong Park9b409bc2019-10-11 14:59:13 +090093
Jiyong Park73c54ee2019-10-22 20:31:18 +090094func (lib *archSpecificNativeLibInfo) signature() string {
95 return fmt.Sprintf("%v %v %v %v",
96 lib.name,
97 lib.exportedIncludeDirs.Strings(),
98 lib.exportedSystemIncludeDirs.Strings(),
99 lib.exportedFlags)
100}
101
102// nativeLibInfo represents a collection of arch-specific modules having the same name
103type nativeLibInfo struct {
104 name string
105 archVariants []archSpecificNativeLibInfo
106 // hasArchSpecificFlags is set to true if modules for each architecture all have the same
107 // include dirs, flags, etc, in which case only those of the first arch is selected.
108 hasArchSpecificFlags bool
109}
110
111// nativeMemberInfos collects all cc.Modules that are member of an SDK.
112func (s *sdk) nativeMemberInfos(ctx android.ModuleContext) []*nativeLibInfo {
113 infoMap := make(map[string]*nativeLibInfo)
114
115 // Collect cc.Modules
116 ctx.VisitDirectDeps(func(m android.Module) {
117 ccModule, ok := m.(*cc.Module)
118 if !ok {
119 return
120 }
121 depName := ctx.OtherModuleName(m)
122
123 if _, ok := infoMap[depName]; !ok {
124 infoMap[depName] = &nativeLibInfo{name: depName}
125 }
126
127 info := infoMap[depName]
128 info.archVariants = append(info.archVariants, archSpecificNativeLibInfo{
129 name: ccModule.BaseModuleName(),
130 archType: ccModule.Target().Arch.ArchType.String(),
131 exportedIncludeDirs: ccModule.ExportedIncludeDirs(),
132 exportedSystemIncludeDirs: ccModule.ExportedSystemIncludeDirs(),
133 exportedFlags: ccModule.ExportedFlags(),
Jiyong Park232e7852019-11-04 12:23:40 +0900134 exportedDeps: ccModule.ExportedDeps(),
Jiyong Park73c54ee2019-10-22 20:31:18 +0900135 outputFile: ccModule.OutputFile().Path(),
136 })
137 })
138
139 // Determine if include dirs and flags for each module are different across arch-specific
140 // modules or not. And set hasArchSpecificFlags accordingly
141 for _, info := range infoMap {
142 // by default, include paths and flags are assumed to be the same across arches
143 info.hasArchSpecificFlags = false
144 oldSignature := ""
145 for _, av := range info.archVariants {
146 newSignature := av.signature()
147 if oldSignature == "" {
148 oldSignature = newSignature
149 }
150 if oldSignature != newSignature {
151 info.hasArchSpecificFlags = true
152 break
153 }
154 }
Jiyong Park9b409bc2019-10-11 14:59:13 +0900155 }
156
Jiyong Park73c54ee2019-10-22 20:31:18 +0900157 var list []*nativeLibInfo
158 for _, v := range infoMap {
159 list = append(list, v)
160 }
161 return list
162}
Jiyong Park9b409bc2019-10-11 14:59:13 +0900163
Jiyong Park73c54ee2019-10-22 20:31:18 +0900164// SDK directory structure
165// <sdk_root>/
166// Android.bp : definition of a 'sdk' module is here. This is a hand-made one.
167// <api_ver>/ : below this directory are all auto-generated
168// Android.bp : definition of 'sdk_snapshot' module is here
169// aidl/
170// frameworks/base/core/..../IFoo.aidl : an exported AIDL file
171// java/
Jiyong Park232e7852019-11-04 12:23:40 +0900172// <module_name>.jar : the stub jar for a java library 'module_name'
Jiyong Park73c54ee2019-10-22 20:31:18 +0900173// include/
174// bionic/libc/include/stdlib.h : an exported header file
175// include_gen/
Jiyong Park232e7852019-11-04 12:23:40 +0900176// <module_name>/com/android/.../IFoo.h : a generated header file
Jiyong Park73c54ee2019-10-22 20:31:18 +0900177// <arch>/include/ : arch-specific exported headers
178// <arch>/include_gen/ : arch-specific generated headers
179// <arch>/lib/
180// libFoo.so : a stub library
181
182const (
183 aidlIncludeDir = "aidl"
184 javaStubDir = "java"
Jiyong Park232e7852019-11-04 12:23:40 +0900185 javaStubFileSuffix = ".jar"
Jiyong Park73c54ee2019-10-22 20:31:18 +0900186 nativeIncludeDir = "include"
187 nativeGeneratedIncludeDir = "include_gen"
188 nativeStubDir = "lib"
189 nativeStubFileSuffix = ".so"
190)
191
192// path to the stub file of a java library. Relative to <sdk_root>/<api_dir>
193func javaStubFilePathFor(javaLib *java.Library) string {
Jiyong Park232e7852019-11-04 12:23:40 +0900194 return filepath.Join(javaStubDir, javaLib.Name()+javaStubFileSuffix)
Jiyong Park73c54ee2019-10-22 20:31:18 +0900195}
196
197// path to the stub file of a native shared library. Relative to <sdk_root>/<api_dir>
198func nativeStubFilePathFor(lib archSpecificNativeLibInfo) string {
199 return filepath.Join(lib.archType,
200 nativeStubDir, lib.name+nativeStubFileSuffix)
201}
202
203// paths to the include dirs of a native shared library. Relative to <sdk_root>/<api_dir>
204func nativeIncludeDirPathsFor(ctx android.ModuleContext, lib archSpecificNativeLibInfo,
205 systemInclude bool, archSpecific bool) []string {
206 var result []string
Jiyong Park73c54ee2019-10-22 20:31:18 +0900207 var includeDirs []android.Path
208 if !systemInclude {
209 includeDirs = lib.exportedIncludeDirs
210 } else {
211 includeDirs = lib.exportedSystemIncludeDirs
212 }
213 for _, dir := range includeDirs {
214 var path string
Jiyong Park232e7852019-11-04 12:23:40 +0900215 if _, gen := dir.(android.WritablePath); gen {
216 path = filepath.Join(nativeGeneratedIncludeDir, lib.name)
Jiyong Park73c54ee2019-10-22 20:31:18 +0900217 } else {
218 path = filepath.Join(nativeIncludeDir, dir.String())
219 }
220 if archSpecific {
221 path = filepath.Join(lib.archType, path)
222 }
223 result = append(result, path)
224 }
225 return result
226}
227
Jiyong Park232e7852019-11-04 12:23:40 +0900228// A name that uniquely identifies a prebuilt SDK member for a version of SDK snapshot
Jiyong Park73c54ee2019-10-22 20:31:18 +0900229// This isn't visible to users, so could be changed in future.
230func versionedSdkMemberName(ctx android.ModuleContext, memberName string, version string) string {
231 return ctx.ModuleName() + "_" + memberName + string(android.SdkVersionSeparator) + version
232}
233
Jiyong Park73c54ee2019-10-22 20:31:18 +0900234// buildAndroidBp creates the blueprint file that defines prebuilt modules for each of
235// the SDK members, and the entire sdk_snapshot module for the specified version
Jiyong Park232e7852019-11-04 12:23:40 +0900236// TODO(jiyong): create a meta info file (e.g. json, protobuf, etc.) instead, and convert it to
237// Android.bp in the (presumably old) branch where the snapshots will be used. This will give us
238// some flexibility to introduce backwards incompatible changes in soong.
Jiyong Park73c54ee2019-10-22 20:31:18 +0900239func (s *sdk) buildAndroidBp(ctx android.ModuleContext, version string) android.OutputPath {
Jiyong Park232e7852019-11-04 12:23:40 +0900240 bp := newGeneratedFile(ctx, "snapshot", "Android.bp")
Jiyong Park73c54ee2019-10-22 20:31:18 +0900241 bp.printfln("// This is auto-generated. DO NOT EDIT.")
242 bp.printfln("")
243
244 javaLibModules := s.javaLibs(ctx)
245 for _, m := range javaLibModules {
246 name := m.Name()
Jiyong Park9b409bc2019-10-11 14:59:13 +0900247 bp.printfln("java_import {")
Jiyong Park73c54ee2019-10-22 20:31:18 +0900248 bp.indent()
249 bp.printfln("name: %q,", versionedSdkMemberName(ctx, name, version))
250 bp.printfln("sdk_member_name: %q,", name)
251 bp.printfln("jars: [%q],", javaStubFilePathFor(m))
252 bp.dedent()
Jiyong Park9b409bc2019-10-11 14:59:13 +0900253 bp.printfln("}")
254 bp.printfln("")
255
256 // This module is for the case when the source tree for the unversioned module
257 // doesn't exist (i.e. building in an unbundled tree). "prefer:" is set to false
258 // so that this module does not eclipse the unversioned module if it exists.
259 bp.printfln("java_import {")
Jiyong Park73c54ee2019-10-22 20:31:18 +0900260 bp.indent()
261 bp.printfln("name: %q,", name)
262 bp.printfln("jars: [%q],", javaStubFilePathFor(m))
263 bp.printfln("prefer: false,")
264 bp.dedent()
Jiyong Park9b409bc2019-10-11 14:59:13 +0900265 bp.printfln("}")
266 bp.printfln("")
Jiyong Park9b409bc2019-10-11 14:59:13 +0900267 }
268
Jiyong Park73c54ee2019-10-22 20:31:18 +0900269 nativeLibInfos := s.nativeMemberInfos(ctx)
270 for _, info := range nativeLibInfos {
271 bp.printfln("cc_prebuilt_library_shared {")
272 bp.indent()
273 bp.printfln("name: %q,", versionedSdkMemberName(ctx, info.name, version))
274 bp.printfln("sdk_member_name: %q,", info.name)
275
276 // a function for emitting include dirs
277 printExportedDirsForNativeLibs := func(lib archSpecificNativeLibInfo, systemInclude bool) {
278 includeDirs := nativeIncludeDirPathsFor(ctx, lib, systemInclude, info.hasArchSpecificFlags)
279 if len(includeDirs) == 0 {
280 return
281 }
282 if !systemInclude {
283 bp.printfln("export_include_dirs: [")
284 } else {
285 bp.printfln("export_system_include_dirs: [")
286 }
287 bp.indent()
288 for _, dir := range includeDirs {
289 bp.printfln("%q,", dir)
290 }
291 bp.dedent()
292 bp.printfln("],")
293 }
294
295 if !info.hasArchSpecificFlags {
296 printExportedDirsForNativeLibs(info.archVariants[0], false /*systemInclude*/)
297 printExportedDirsForNativeLibs(info.archVariants[0], true /*systemInclude*/)
298 }
299
300 bp.printfln("arch: {")
301 bp.indent()
302 for _, av := range info.archVariants {
303 bp.printfln("%s: {", av.archType)
304 bp.indent()
305 bp.printfln("srcs: [%q],", nativeStubFilePathFor(av))
306 if info.hasArchSpecificFlags {
307 // export_* properties are added inside the arch: {<arch>: {...}} block
308 printExportedDirsForNativeLibs(av, false /*systemInclude*/)
309 printExportedDirsForNativeLibs(av, true /*systemInclude*/)
310 }
311 bp.dedent()
312 bp.printfln("},") // <arch>
313 }
314 bp.dedent()
315 bp.printfln("},") // arch
316 bp.printfln("stl: \"none\",")
317 bp.printfln("system_shared_libs: [],")
318 bp.dedent()
319 bp.printfln("}") // cc_prebuilt_library_shared
320 bp.printfln("")
321 }
Jiyong Park9b409bc2019-10-11 14:59:13 +0900322
323 bp.printfln("sdk_snapshot {")
Jiyong Park73c54ee2019-10-22 20:31:18 +0900324 bp.indent()
325 bp.printfln("name: %q,", ctx.ModuleName()+string(android.SdkVersionSeparator)+version)
326 if len(javaLibModules) > 0 {
327 bp.printfln("java_libs: [")
328 bp.indent()
329 for _, m := range javaLibModules {
330 bp.printfln("%q,", versionedSdkMemberName(ctx, m.Name(), version))
331 }
332 bp.dedent()
333 bp.printfln("],") // java_libs
Jiyong Park9b409bc2019-10-11 14:59:13 +0900334 }
Jiyong Park73c54ee2019-10-22 20:31:18 +0900335 if len(nativeLibInfos) > 0 {
336 bp.printfln("native_shared_libs: [")
337 bp.indent()
338 for _, info := range nativeLibInfos {
339 bp.printfln("%q,", versionedSdkMemberName(ctx, info.name, version))
340 }
341 bp.dedent()
342 bp.printfln("],") // native_shared_libs
343 }
344 bp.dedent()
345 bp.printfln("}") // sdk_snapshot
Jiyong Park9b409bc2019-10-11 14:59:13 +0900346 bp.printfln("")
347
348 bp.build(pctx, ctx, nil)
349 return bp.path
350}
351
Jiyong Park232e7852019-11-04 12:23:40 +0900352// buildSnapshot is the main function in this source file. It creates rules to copy
353// the contents (header files, stub libraries, etc) into the zip file.
354func (s *sdk) buildSnapshot(ctx android.ModuleContext) android.OutputPath {
355 snapshotPath := func(paths ...string) android.OutputPath {
356 return android.PathForModuleOut(ctx, "snapshot").Join(ctx, paths...)
Jiyong Park73c54ee2019-10-22 20:31:18 +0900357 }
Jiyong Park9b409bc2019-10-11 14:59:13 +0900358
Jiyong Park232e7852019-11-04 12:23:40 +0900359 var filesToZip android.Paths
360 // copy src to dest and add the dest to the zip
361 copy := func(src android.Path, dest android.OutputPath) {
362 ctx.Build(pctx, android.BuildParams{
363 Rule: android.Cp,
364 Input: src,
365 Output: dest,
366 })
367 filesToZip = append(filesToZip, dest)
Jiyong Park73c54ee2019-10-22 20:31:18 +0900368 }
Jiyong Park9b409bc2019-10-11 14:59:13 +0900369
Jiyong Park232e7852019-11-04 12:23:40 +0900370 // copy exported AIDL files and stub jar files
Jiyong Park73c54ee2019-10-22 20:31:18 +0900371 for _, m := range s.javaLibs(ctx) {
372 headerJars := m.HeaderJars()
373 if len(headerJars) != 1 {
374 panic(fmt.Errorf("there must be only one header jar from %q", m.Name()))
Jiyong Park9b409bc2019-10-11 14:59:13 +0900375 }
Jiyong Park232e7852019-11-04 12:23:40 +0900376 copy(headerJars[0], snapshotPath(javaStubFilePathFor(m)))
Jiyong Park73c54ee2019-10-22 20:31:18 +0900377
Jiyong Park232e7852019-11-04 12:23:40 +0900378 for _, dir := range m.AidlIncludeDirs() {
Jiyong Park73c54ee2019-10-22 20:31:18 +0900379 // TODO(jiyong): copy parcelable declarations only
Jiyong Park232e7852019-11-04 12:23:40 +0900380 aidlFiles, _ := ctx.GlobWithDeps(dir.String()+"/**/*.aidl", nil)
381 for _, file := range aidlFiles {
382 copy(android.PathForSource(ctx, file), snapshotPath(aidlIncludeDir, file))
383 }
Jiyong Park73c54ee2019-10-22 20:31:18 +0900384 }
Jiyong Park73c54ee2019-10-22 20:31:18 +0900385 }
386
Jiyong Park232e7852019-11-04 12:23:40 +0900387 // copy exported header files and stub *.so files
Jiyong Park73c54ee2019-10-22 20:31:18 +0900388 nativeLibInfos := s.nativeMemberInfos(ctx)
389 for _, info := range nativeLibInfos {
390
391 // a function for emitting include dirs
392 printExportedDirCopyCommandsForNativeLibs := func(lib archSpecificNativeLibInfo) {
393 includeDirs := lib.exportedIncludeDirs
394 includeDirs = append(includeDirs, lib.exportedSystemIncludeDirs...)
395 if len(includeDirs) == 0 {
396 return
397 }
398 for _, dir := range includeDirs {
Jiyong Park232e7852019-11-04 12:23:40 +0900399 if _, gen := dir.(android.WritablePath); gen {
400 // generated headers are copied via exportedDeps. See below.
401 continue
Jiyong Park73c54ee2019-10-22 20:31:18 +0900402 }
Jiyong Park232e7852019-11-04 12:23:40 +0900403 targetDir := nativeIncludeDir
Jiyong Park73c54ee2019-10-22 20:31:18 +0900404 if info.hasArchSpecificFlags {
405 targetDir = filepath.Join(lib.archType, targetDir)
406 }
Jiyong Park73c54ee2019-10-22 20:31:18 +0900407
Jiyong Park73c54ee2019-10-22 20:31:18 +0900408 // TODO(jiyong) copy headers having other suffixes
Jiyong Park232e7852019-11-04 12:23:40 +0900409 headers, _ := ctx.GlobWithDeps(dir.String()+"/**/*.h", nil)
410 for _, file := range headers {
411 src := android.PathForSource(ctx, file)
412 dest := snapshotPath(targetDir, file)
413 copy(src, dest)
414 }
415 }
416
417 genHeaders := lib.exportedDeps
418 for _, file := range genHeaders {
419 targetDir := nativeGeneratedIncludeDir
420 if info.hasArchSpecificFlags {
421 targetDir = filepath.Join(lib.archType, targetDir)
422 }
423 dest := snapshotPath(targetDir, lib.name, file.Rel())
424 copy(file, dest)
Jiyong Park73c54ee2019-10-22 20:31:18 +0900425 }
426 }
427
428 if !info.hasArchSpecificFlags {
429 printExportedDirCopyCommandsForNativeLibs(info.archVariants[0])
430 }
431
432 // for each architecture
433 for _, av := range info.archVariants {
Jiyong Park232e7852019-11-04 12:23:40 +0900434 copy(av.outputFile, snapshotPath(nativeStubFilePathFor(av)))
Jiyong Park73c54ee2019-10-22 20:31:18 +0900435
436 if info.hasArchSpecificFlags {
437 printExportedDirCopyCommandsForNativeLibs(av)
438 }
439 }
440 }
Jiyong Park9b409bc2019-10-11 14:59:13 +0900441
Jiyong Park232e7852019-11-04 12:23:40 +0900442 // generate Android.bp
443 bp := s.buildAndroidBp(ctx, "current")
444 filesToZip = append(filesToZip, bp)
Jiyong Park9b409bc2019-10-11 14:59:13 +0900445
Jiyong Park232e7852019-11-04 12:23:40 +0900446 // zip them all
447 zipFile := android.PathForModuleOut(ctx, ctx.ModuleName()+"-current.zip").OutputPath
448 rb := android.NewRuleBuilder()
449 rb.Command().
450 BuiltTool(ctx, "soong_zip").
451 FlagWithArg("-C ", snapshotPath().String()).
452 FlagWithRspFileInputList("-l ", filesToZip).
453 FlagWithOutput("-o ", zipFile)
454 rb.Build(pctx, ctx, "snapshot", "Building snapshot for "+ctx.ModuleName())
Jiyong Park9b409bc2019-10-11 14:59:13 +0900455
Jiyong Park232e7852019-11-04 12:23:40 +0900456 return zipFile
Jiyong Park9b409bc2019-10-11 14:59:13 +0900457}