blob: 562186eaf21c41752fc67e49473c6fb36a5e4a6e [file] [log] [blame]
Dan Albert914449f2016-06-17 16:45:24 -07001// Copyright 2016 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 "fmt"
19 "strconv"
20 "strings"
21
22 "github.com/google/blueprint"
23
24 "android/soong/android"
25)
26
27var (
28 toolPath = pctx.SourcePathVariable("toolPath", "build/soong/cc/gen_stub_libs.py")
29
30 genStubSrc = pctx.StaticRule("genStubSrc",
31 blueprint.RuleParams{
32 Command: "$toolPath --arch $arch --api $apiLevel $in $out",
33 Description: "genStubSrc $out",
34 CommandDeps: []string{"$toolPath"},
35 }, "arch", "apiLevel")
36
37 ndkLibrarySuffix = ".ndk"
38)
39
40// Creates a stub shared library based on the provided version file.
41//
42// The name of the generated file will be based on the module name by stripping
43// the ".ndk" suffix from the module name. Module names must end with ".ndk"
44// (as a convention to allow soong to guess the NDK name of a dependency when
45// needed). "libfoo.ndk" will generate "libfoo.so.
46//
47// Example:
48//
49// ndk_library {
50// name: "libfoo.ndk",
51// symbol_file: "libfoo.map.txt",
52// first_version: "9",
53// }
54//
55type libraryProperties struct {
56 // Relative path to the symbol map.
57 // An example file can be seen here: TODO(danalbert): Make an example.
58 Symbol_file string
59
60 // The first API level a library was available. A library will be generated
61 // for every API level beginning with this one.
62 First_version string
63
64 // Private property for use by the mutator that splits per-API level.
65 ApiLevel int `blueprint:"mutated"`
66}
67
68type stubCompiler struct {
69 baseCompiler
70
71 properties libraryProperties
72}
73
74// OMG GO
75func intMin(a int, b int) int {
76 if a < b {
77 return a
78 } else {
79 return b
80 }
81}
82
83func generateStubApiVariants(mctx android.BottomUpMutatorContext, c *stubCompiler) {
84 minVersion := 9 // Minimum version supported by the NDK.
85 // TODO(danalbert): Use PlatformSdkVersion when possible.
86 // This is an interesting case because for the moment we actually need 24
87 // even though the latest released version in aosp is 23. prebuilts/ndk/r11
88 // has android-24 versions of libraries, and as platform libraries get
89 // migrated the libraries in prebuilts will need to depend on them.
90 //
91 // Once everything is all moved over to the new stuff (when there isn't a
92 // prebuilts/ndk any more) then this should be fixable, but for now I think
93 // it needs to remain as-is.
94 maxVersion := 24
95 firstArchVersions := map[string]int{
96 "arm": 9,
97 "arm64": 21,
98 "mips": 9,
99 "mips64": 21,
100 "x86": 9,
101 "x86_64": 21,
102 }
103
104 // If the NDK drops support for a platform version, we don't want to have to
105 // fix up every module that was using it as its minimum version. Clip to the
106 // supported version here instead.
107 firstVersion, err := strconv.Atoi(c.properties.First_version)
108 if err != nil {
109 mctx.ModuleErrorf("Invalid first_version value (must be int): %q",
110 c.properties.First_version)
111 }
112 if firstVersion < minVersion {
113 firstVersion = minVersion
114 }
115
116 arch := mctx.Arch().ArchType.String()
117 firstArchVersion, ok := firstArchVersions[arch]
118 if !ok {
119 panic(fmt.Errorf("Arch %q not found in firstArchVersions", arch))
120 }
121 firstGenVersion := intMin(firstVersion, firstArchVersion)
122 versionStrs := make([]string, maxVersion-firstGenVersion+1)
123 for version := firstGenVersion; version <= maxVersion; version++ {
124 versionStrs[version-firstGenVersion] = strconv.Itoa(version)
125 }
126
127 modules := mctx.CreateVariations(versionStrs...)
128 for i, module := range modules {
129 module.(*Module).compiler.(*stubCompiler).properties.ApiLevel = firstGenVersion + i
130 }
131}
132
133func ndkApiMutator(mctx android.BottomUpMutatorContext) {
134 if m, ok := mctx.Module().(*Module); ok {
135 if compiler, ok := m.compiler.(*stubCompiler); ok {
136 generateStubApiVariants(mctx, compiler)
137 }
138 }
139}
140
141func (c *stubCompiler) compile(ctx ModuleContext, flags Flags, deps PathDeps) android.Paths {
142 arch := ctx.Arch().ArchType.String()
143
144 if !strings.HasSuffix(ctx.ModuleName(), ndkLibrarySuffix) {
145 ctx.ModuleErrorf("ndk_library modules names must be suffixed with %q\n",
146 ndkLibrarySuffix)
147 }
148 libName := strings.TrimSuffix(ctx.ModuleName(), ndkLibrarySuffix)
149 fileBase := fmt.Sprintf("%s.%s.%d", libName, arch, c.properties.ApiLevel)
150 stubSrcName := fileBase + ".c"
151 stubSrcPath := android.PathForModuleGen(ctx, stubSrcName)
152 versionScriptName := fileBase + ".map"
153 versionScriptPath := android.PathForModuleGen(ctx, versionScriptName)
154 symbolFilePath := android.PathForModuleSrc(ctx, c.properties.Symbol_file)
155 ctx.ModuleBuild(pctx, android.ModuleBuildParams{
156 Rule: genStubSrc,
157 Outputs: []android.WritablePath{stubSrcPath, versionScriptPath},
158 Input: symbolFilePath,
159 Args: map[string]string{
160 "arch": arch,
161 "apiLevel": strconv.Itoa(c.properties.ApiLevel),
162 },
163 })
164
165 flags.CFlags = append(flags.CFlags,
166 // We're knowingly doing some otherwise unsightly things with builtin
167 // functions here. We're just generating stub libraries, so ignore it.
168 "-Wno-incompatible-library-redeclaration",
169 "-Wno-builtin-requires-header",
170 "-Wno-invalid-noreturn",
171
172 // These libraries aren't actually used. Don't worry about unwinding
173 // (avoids the need to link an unwinder into a fake library).
174 "-fno-unwind-tables",
175 )
176
177 subdir := ""
178 srcs := []string{}
179 excludeSrcs := []string{}
180 extraSrcs := []android.Path{stubSrcPath}
181 extraDeps := []android.Path{}
182 return c.baseCompiler.compileObjs(ctx, flags, subdir, srcs, excludeSrcs,
183 extraSrcs, extraDeps)
184}
185
186type stubLinker struct {
187 libraryLinker
188}
189
190func (linker *stubLinker) deps(ctx BaseModuleContext, deps Deps) Deps {
191 return Deps{}
192}
193
194func (linker *stubLinker) flags(ctx ModuleContext, flags Flags) Flags {
195 linker.libraryLinker.libName = strings.TrimSuffix(ctx.ModuleName(),
196 ndkLibrarySuffix)
197 return linker.libraryLinker.flags(ctx, flags)
198}
199
200type stubInstaller struct {
201 baseInstaller
202
203 compiler *stubCompiler
204
205 installPath string
206}
207
208var _ installer = (*stubInstaller)(nil)
209
210func (installer *stubInstaller) install(ctx ModuleContext, path android.Path) {
211 arch := ctx.Target().Arch.ArchType.Name
212 apiLevel := installer.compiler.properties.ApiLevel
213
214 // arm64 isn't actually a multilib toolchain, so unlike the other LP64
215 // architectures it's just installed to lib.
216 libDir := "lib"
217 if ctx.toolchain().Is64Bit() && arch != "arm64" {
218 libDir = "lib64"
219 }
220
221 installDir := getNdkInstallBase(ctx).Join(ctx, fmt.Sprintf(
222 "platforms/android-%d/arch-%s/usr/%s", apiLevel, arch, libDir))
223 installer.installPath = ctx.InstallFile(installDir, path).String()
224}
225
226func newStubLibrary() *Module {
227 module := newModule(android.DeviceSupported, android.MultilibBoth)
228 module.stl = nil
229
230 linker := &stubLinker{}
231 linker.dynamicProperties.BuildShared = true
232 linker.dynamicProperties.BuildStatic = false
233 linker.stripper.StripProperties.Strip.None = true
234 module.linker = linker
235
236 compiler := &stubCompiler{}
237 module.compiler = compiler
238 module.installer = &stubInstaller{baseInstaller{
239 dir: "lib",
240 dir64: "lib64",
241 }, compiler, ""}
242
243 return module
244}
245
246func ndkLibraryFactory() (blueprint.Module, []interface{}) {
247 module := newStubLibrary()
248 return android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibBoth,
249 &module.compiler.(*stubCompiler).properties)
250}