blob: 515327a67dcc7423a0242e953a5e6e5e2ab142da [file] [log] [blame]
Colin Cross3f40fa42015-01-30 17:27:36 -08001// Copyright 2015 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 common
16
17import (
18 "blueprint"
19 "path/filepath"
20)
21
22var (
23 DeviceSharedLibrary = "shared_library"
24 DeviceStaticLibrary = "static_library"
25 DeviceExecutable = "executable"
26 HostSharedLibrary = "host_shared_library"
27 HostStaticLibrary = "host_static_library"
28 HostExecutable = "host_executable"
29)
30
31type AndroidModuleContext interface {
32 blueprint.ModuleContext
33
34 Arch() Arch
35 InstallFile(installPath, srcPath string)
36 CheckbuildFile(srcPath string)
37}
38
39type AndroidModule interface {
40 blueprint.Module
41
42 GenerateAndroidBuildActions(AndroidModuleContext)
43
44 base() *AndroidModuleBase
45 Disabled() bool
46 HostOrDevice() HostOrDevice
47}
48
49type AndroidDynamicDepender interface {
50 AndroidDynamicDependencies(ctx AndroidDynamicDependerModuleContext) []string
51}
52
53type AndroidDynamicDependerModuleContext interface {
54 blueprint.DynamicDependerModuleContext
55}
56
57type commonProperties struct {
58 Name string
59 Deps []string
60 ResourceDirs []string
61
62 // disabled: don't emit any build rules for this module
63 Disabled bool `android:"arch_variant"`
64
65 // multilib: control whether this module compiles for 32-bit, 64-bit, or both. Possible values
66 // are "32" (compile for 32-bit only), "64" (compile for 64-bit only), "both" (compile for both
67 // architectures), or "first" (compile for 64-bit on a 64-bit platform, and 32-bit on a 32-bit
68 // platform
69 Compile_multilib string
70
71 // Set by ArchMutator
72 CompileArch Arch `blueprint:"mutated"`
73
74 // Set by InitAndroidModule
75 HostOrDeviceSupported HostOrDeviceSupported `blueprint:"mutated"`
76}
77
78type hostAndDeviceProperties struct {
79 Host_supported bool
80 Device_supported bool
81}
82
83func InitAndroidModule(m AndroidModule, hod HostOrDeviceSupported, defaultMultilib string,
84 propertyStructs ...interface{}) (blueprint.Module, []interface{}) {
85
86 base := m.base()
87 base.module = m
88 base.commonProperties.HostOrDeviceSupported = hod
89
90 if hod == HostAndDeviceSupported {
91 // Default to module to device supported, host not supported, can override in module
92 // properties
93 base.hostAndDeviceProperties.Device_supported = true
94 propertyStructs = append(propertyStructs, &base.hostAndDeviceProperties)
95 }
96
97 return InitArchModule(m, defaultMultilib, propertyStructs...)
98}
99
100// A AndroidModuleBase object contains the properties that are common to all Android
101// modules. It should be included as an anonymous field in every module
102// struct definition. InitAndroidModule should then be called from the module's
103// factory function, and the return values from InitAndroidModule should be
104// returned from the factory function.
105//
106// The AndroidModuleBase type is responsible for implementing the
107// GenerateBuildActions method to support the blueprint.Module interface. This
108// method will then call the module's GenerateAndroidBuildActions method once
109// for each build variant that is to be built. GenerateAndroidBuildActions is
110// passed a AndroidModuleContext rather than the usual blueprint.ModuleContext.
111// AndroidModuleContext exposes extra functionality specific to the Android build
112// system including details about the particular build variant that is to be
113// generated.
114//
115// For example:
116//
117// import (
118// "android/soong/common"
119// "blueprint"
120// )
121//
122// type myModule struct {
123// common.AndroidModuleBase
124// properties struct {
125// MyProperty string
126// }
127// }
128//
129// func NewMyModule() (blueprint.Module, []interface{}) {
130// m := &myModule{}
131// return common.InitAndroidModule(m, &m.properties)
132// }
133//
134// func (m *myModule) GenerateAndroidBuildActions(ctx common.AndroidModuleContext) {
135// // Get the CPU architecture for the current build variant.
136// variantArch := ctx.Arch()
137//
138// // ...
139// }
140type AndroidModuleBase struct {
141 // Putting the curiously recurring thing pointing to the thing that contains
142 // the thing pattern to good use.
143 module AndroidModule
144
145 commonProperties commonProperties
146 hostAndDeviceProperties hostAndDeviceProperties
147 generalProperties []interface{}
148 archProperties []*archProperties
149
150 noAddressSanitizer bool
151 installFiles []string
152 checkbuildFiles []string
153}
154
155func (a *AndroidModuleBase) base() *AndroidModuleBase {
156 return a
157}
158
159func (a *AndroidModuleBase) SetArch(arch Arch) {
160 a.commonProperties.CompileArch = arch
161}
162
163func (a *AndroidModuleBase) HostOrDevice() HostOrDevice {
164 return a.commonProperties.CompileArch.HostOrDevice
165}
166
167func (a *AndroidModuleBase) HostSupported() bool {
168 return a.commonProperties.HostOrDeviceSupported == HostSupported ||
169 a.commonProperties.HostOrDeviceSupported == HostAndDeviceSupported &&
170 a.hostAndDeviceProperties.Host_supported
171}
172
173func (a *AndroidModuleBase) DeviceSupported() bool {
174 return a.commonProperties.HostOrDeviceSupported == DeviceSupported ||
175 a.commonProperties.HostOrDeviceSupported == HostAndDeviceSupported &&
176 a.hostAndDeviceProperties.Device_supported
177}
178
179func (a *AndroidModuleBase) Disabled() bool {
180 return a.commonProperties.Disabled
181}
182
183func (a *AndroidModuleBase) computeInstallDeps(
184 ctx blueprint.ModuleContext) []string {
185
186 result := []string{}
187 ctx.VisitDepsDepthFirstIf(isFileInstaller,
188 func(m blueprint.Module) {
189 fileInstaller := m.(fileInstaller)
190 files := fileInstaller.filesToInstall()
191 result = append(result, files...)
192 })
193
194 return result
195}
196
197func (a *AndroidModuleBase) filesToInstall() []string {
198 return a.installFiles
199}
200
201func (p *AndroidModuleBase) NoAddressSanitizer() bool {
202 return p.noAddressSanitizer
203}
204
205func (p *AndroidModuleBase) resourceDirs() []string {
206 return p.commonProperties.ResourceDirs
207}
208
209func (a *AndroidModuleBase) generateModuleTarget(ctx blueprint.ModuleContext) {
210 if a != ctx.FinalModule().(AndroidModule).base() {
211 return
212 }
213
214 allInstalledFiles := []string{}
Colin Cross9454bfa2015-03-17 13:24:18 -0700215 allCheckbuildFiles := []string{}
Colin Cross3f40fa42015-01-30 17:27:36 -0800216 ctx.VisitAllModuleVariants(func(module blueprint.Module) {
217 if androidModule, ok := module.(AndroidModule); ok {
218 files := androidModule.base().installFiles
219 allInstalledFiles = append(allInstalledFiles, files...)
Colin Cross9454bfa2015-03-17 13:24:18 -0700220 files = androidModule.base().checkbuildFiles
221 allCheckbuildFiles = append(allCheckbuildFiles, files...)
Colin Cross3f40fa42015-01-30 17:27:36 -0800222 }
223 })
224
Colin Cross9454bfa2015-03-17 13:24:18 -0700225 deps := []string{}
226
Colin Cross3f40fa42015-01-30 17:27:36 -0800227 if len(allInstalledFiles) > 0 {
Colin Cross9454bfa2015-03-17 13:24:18 -0700228 name := ctx.ModuleName() + "-install"
Colin Cross3f40fa42015-01-30 17:27:36 -0800229 ctx.Build(pctx, blueprint.BuildParams{
Colin Cross9454bfa2015-03-17 13:24:18 -0700230 Rule: blueprint.Phony,
231 Outputs: []string{name},
232 Implicits: allInstalledFiles,
233 })
234 deps = append(deps, name)
235 }
236
237 if len(allCheckbuildFiles) > 0 {
238 name := ctx.ModuleName() + "-checkbuild"
239 ctx.Build(pctx, blueprint.BuildParams{
240 Rule: blueprint.Phony,
241 Outputs: []string{name},
242 Implicits: allCheckbuildFiles,
243 Optional: true,
244 })
245 deps = append(deps, name)
246 }
247
248 if len(deps) > 0 {
249 ctx.Build(pctx, blueprint.BuildParams{
250 Rule: blueprint.Phony,
251 Outputs: []string{ctx.ModuleName()},
252 Implicits: deps,
253 Optional: true,
Colin Cross3f40fa42015-01-30 17:27:36 -0800254 })
255 }
256}
257
258func (a *AndroidModuleBase) DynamicDependencies(ctx blueprint.DynamicDependerModuleContext) []string {
259 actx := &androidDynamicDependerContext{
260 DynamicDependerModuleContext: ctx,
261 module: a,
262 }
263
264 if dynamic, ok := a.module.(AndroidDynamicDepender); ok {
265 return dynamic.AndroidDynamicDependencies(actx)
266 }
267
268 return nil
269}
270
271func (a *AndroidModuleBase) GenerateBuildActions(ctx blueprint.ModuleContext) {
272 androidCtx := &androidModuleContext{
273 ModuleContext: ctx,
274 installDeps: a.computeInstallDeps(ctx),
275 installFiles: a.installFiles,
276 arch: a.commonProperties.CompileArch,
277 }
278
279 if a.commonProperties.Disabled {
280 return
281 }
282
283 a.module.GenerateAndroidBuildActions(androidCtx)
284 if ctx.Failed() {
285 return
286 }
287
288 a.generateModuleTarget(ctx)
289 if ctx.Failed() {
290 return
291 }
Colin Cross9454bfa2015-03-17 13:24:18 -0700292
293 a.installFiles = append(a.installFiles, androidCtx.installFiles...)
294 a.checkbuildFiles = append(a.checkbuildFiles, androidCtx.checkbuildFiles...)
Colin Cross3f40fa42015-01-30 17:27:36 -0800295}
296
297type androidModuleContext struct {
298 blueprint.ModuleContext
299 arch Arch
300 installDeps []string
301 installFiles []string
302 checkbuildFiles []string
303}
304
305func (a *androidModuleContext) Build(pctx *blueprint.PackageContext, params blueprint.BuildParams) {
306 params.Optional = true
307 a.ModuleContext.Build(pctx, params)
308}
309
310func (a *androidModuleContext) Arch() Arch {
311 return a.arch
312}
313
314func (a *androidModuleContext) InstallFile(installPath, srcPath string) {
315 var fullInstallPath string
316 if a.arch.HostOrDevice.Device() {
317 // TODO: replace unset with a device name once we have device targeting
318 fullInstallPath = filepath.Join("out/target/product/unset/system", installPath,
319 filepath.Base(srcPath))
320 } else {
321 // TODO: replace unset with a host name
322 fullInstallPath = filepath.Join("out/host/unset/", installPath, filepath.Base(srcPath))
323 }
324
325 a.ModuleContext.Build(pctx, blueprint.BuildParams{
326 Rule: Cp,
327 Outputs: []string{fullInstallPath},
328 Inputs: []string{srcPath},
329 OrderOnly: a.installDeps,
330 })
331
332 a.installFiles = append(a.installFiles, fullInstallPath)
Colin Cross3f40fa42015-01-30 17:27:36 -0800333}
334
335func (a *androidModuleContext) CheckbuildFile(srcPath string) {
336 a.checkbuildFiles = append(a.checkbuildFiles, srcPath)
337}
338
339type androidDynamicDependerContext struct {
340 blueprint.DynamicDependerModuleContext
341 module *AndroidModuleBase
342}
343
344type fileInstaller interface {
345 filesToInstall() []string
346}
347
348func isFileInstaller(m blueprint.Module) bool {
349 _, ok := m.(fileInstaller)
350 return ok
351}
352
353func isAndroidModule(m blueprint.Module) bool {
354 _, ok := m.(AndroidModule)
355 return ok
356}