blob: ba33ec6fa1bc9fe710ace9a651300a4ed2f7c09c [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
Colin Crossc472d572015-03-17 15:06:21 -070083type Multilib string
84
85const (
86 MultilibBoth Multilib = "both"
87 MultilibFirst Multilib = "first"
88)
89
90func InitAndroidModule(m AndroidModule, hod HostOrDeviceSupported, defaultMultilib Multilib,
Colin Cross3f40fa42015-01-30 17:27:36 -080091 propertyStructs ...interface{}) (blueprint.Module, []interface{}) {
92
93 base := m.base()
94 base.module = m
95 base.commonProperties.HostOrDeviceSupported = hod
96
97 if hod == HostAndDeviceSupported {
98 // Default to module to device supported, host not supported, can override in module
99 // properties
100 base.hostAndDeviceProperties.Device_supported = true
101 propertyStructs = append(propertyStructs, &base.hostAndDeviceProperties)
102 }
103
104 return InitArchModule(m, defaultMultilib, propertyStructs...)
105}
106
107// A AndroidModuleBase object contains the properties that are common to all Android
108// modules. It should be included as an anonymous field in every module
109// struct definition. InitAndroidModule should then be called from the module's
110// factory function, and the return values from InitAndroidModule should be
111// returned from the factory function.
112//
113// The AndroidModuleBase type is responsible for implementing the
114// GenerateBuildActions method to support the blueprint.Module interface. This
115// method will then call the module's GenerateAndroidBuildActions method once
116// for each build variant that is to be built. GenerateAndroidBuildActions is
117// passed a AndroidModuleContext rather than the usual blueprint.ModuleContext.
118// AndroidModuleContext exposes extra functionality specific to the Android build
119// system including details about the particular build variant that is to be
120// generated.
121//
122// For example:
123//
124// import (
125// "android/soong/common"
126// "blueprint"
127// )
128//
129// type myModule struct {
130// common.AndroidModuleBase
131// properties struct {
132// MyProperty string
133// }
134// }
135//
136// func NewMyModule() (blueprint.Module, []interface{}) {
137// m := &myModule{}
138// return common.InitAndroidModule(m, &m.properties)
139// }
140//
141// func (m *myModule) GenerateAndroidBuildActions(ctx common.AndroidModuleContext) {
142// // Get the CPU architecture for the current build variant.
143// variantArch := ctx.Arch()
144//
145// // ...
146// }
147type AndroidModuleBase struct {
148 // Putting the curiously recurring thing pointing to the thing that contains
149 // the thing pattern to good use.
150 module AndroidModule
151
152 commonProperties commonProperties
153 hostAndDeviceProperties hostAndDeviceProperties
154 generalProperties []interface{}
155 archProperties []*archProperties
156
157 noAddressSanitizer bool
158 installFiles []string
159 checkbuildFiles []string
160}
161
162func (a *AndroidModuleBase) base() *AndroidModuleBase {
163 return a
164}
165
166func (a *AndroidModuleBase) SetArch(arch Arch) {
167 a.commonProperties.CompileArch = arch
168}
169
170func (a *AndroidModuleBase) HostOrDevice() HostOrDevice {
171 return a.commonProperties.CompileArch.HostOrDevice
172}
173
174func (a *AndroidModuleBase) HostSupported() bool {
175 return a.commonProperties.HostOrDeviceSupported == HostSupported ||
176 a.commonProperties.HostOrDeviceSupported == HostAndDeviceSupported &&
177 a.hostAndDeviceProperties.Host_supported
178}
179
180func (a *AndroidModuleBase) DeviceSupported() bool {
181 return a.commonProperties.HostOrDeviceSupported == DeviceSupported ||
182 a.commonProperties.HostOrDeviceSupported == HostAndDeviceSupported &&
183 a.hostAndDeviceProperties.Device_supported
184}
185
186func (a *AndroidModuleBase) Disabled() bool {
187 return a.commonProperties.Disabled
188}
189
190func (a *AndroidModuleBase) computeInstallDeps(
191 ctx blueprint.ModuleContext) []string {
192
193 result := []string{}
194 ctx.VisitDepsDepthFirstIf(isFileInstaller,
195 func(m blueprint.Module) {
196 fileInstaller := m.(fileInstaller)
197 files := fileInstaller.filesToInstall()
198 result = append(result, files...)
199 })
200
201 return result
202}
203
204func (a *AndroidModuleBase) filesToInstall() []string {
205 return a.installFiles
206}
207
208func (p *AndroidModuleBase) NoAddressSanitizer() bool {
209 return p.noAddressSanitizer
210}
211
212func (p *AndroidModuleBase) resourceDirs() []string {
213 return p.commonProperties.ResourceDirs
214}
215
216func (a *AndroidModuleBase) generateModuleTarget(ctx blueprint.ModuleContext) {
217 if a != ctx.FinalModule().(AndroidModule).base() {
218 return
219 }
220
221 allInstalledFiles := []string{}
Colin Cross9454bfa2015-03-17 13:24:18 -0700222 allCheckbuildFiles := []string{}
Colin Cross3f40fa42015-01-30 17:27:36 -0800223 ctx.VisitAllModuleVariants(func(module blueprint.Module) {
224 if androidModule, ok := module.(AndroidModule); ok {
225 files := androidModule.base().installFiles
226 allInstalledFiles = append(allInstalledFiles, files...)
Colin Cross9454bfa2015-03-17 13:24:18 -0700227 files = androidModule.base().checkbuildFiles
228 allCheckbuildFiles = append(allCheckbuildFiles, files...)
Colin Cross3f40fa42015-01-30 17:27:36 -0800229 }
230 })
231
Colin Cross9454bfa2015-03-17 13:24:18 -0700232 deps := []string{}
233
Colin Cross3f40fa42015-01-30 17:27:36 -0800234 if len(allInstalledFiles) > 0 {
Colin Cross9454bfa2015-03-17 13:24:18 -0700235 name := ctx.ModuleName() + "-install"
Colin Cross3f40fa42015-01-30 17:27:36 -0800236 ctx.Build(pctx, blueprint.BuildParams{
Colin Cross9454bfa2015-03-17 13:24:18 -0700237 Rule: blueprint.Phony,
238 Outputs: []string{name},
239 Implicits: allInstalledFiles,
240 })
241 deps = append(deps, name)
242 }
243
244 if len(allCheckbuildFiles) > 0 {
245 name := ctx.ModuleName() + "-checkbuild"
246 ctx.Build(pctx, blueprint.BuildParams{
247 Rule: blueprint.Phony,
248 Outputs: []string{name},
249 Implicits: allCheckbuildFiles,
250 Optional: true,
251 })
252 deps = append(deps, name)
253 }
254
255 if len(deps) > 0 {
256 ctx.Build(pctx, blueprint.BuildParams{
257 Rule: blueprint.Phony,
258 Outputs: []string{ctx.ModuleName()},
259 Implicits: deps,
260 Optional: true,
Colin Cross3f40fa42015-01-30 17:27:36 -0800261 })
262 }
263}
264
265func (a *AndroidModuleBase) DynamicDependencies(ctx blueprint.DynamicDependerModuleContext) []string {
266 actx := &androidDynamicDependerContext{
267 DynamicDependerModuleContext: ctx,
268 module: a,
269 }
270
271 if dynamic, ok := a.module.(AndroidDynamicDepender); ok {
272 return dynamic.AndroidDynamicDependencies(actx)
273 }
274
275 return nil
276}
277
278func (a *AndroidModuleBase) GenerateBuildActions(ctx blueprint.ModuleContext) {
279 androidCtx := &androidModuleContext{
280 ModuleContext: ctx,
281 installDeps: a.computeInstallDeps(ctx),
282 installFiles: a.installFiles,
283 arch: a.commonProperties.CompileArch,
284 }
285
286 if a.commonProperties.Disabled {
287 return
288 }
289
290 a.module.GenerateAndroidBuildActions(androidCtx)
291 if ctx.Failed() {
292 return
293 }
294
295 a.generateModuleTarget(ctx)
296 if ctx.Failed() {
297 return
298 }
Colin Cross9454bfa2015-03-17 13:24:18 -0700299
300 a.installFiles = append(a.installFiles, androidCtx.installFiles...)
301 a.checkbuildFiles = append(a.checkbuildFiles, androidCtx.checkbuildFiles...)
Colin Cross3f40fa42015-01-30 17:27:36 -0800302}
303
304type androidModuleContext struct {
305 blueprint.ModuleContext
306 arch Arch
307 installDeps []string
308 installFiles []string
309 checkbuildFiles []string
310}
311
312func (a *androidModuleContext) Build(pctx *blueprint.PackageContext, params blueprint.BuildParams) {
313 params.Optional = true
314 a.ModuleContext.Build(pctx, params)
315}
316
317func (a *androidModuleContext) Arch() Arch {
318 return a.arch
319}
320
321func (a *androidModuleContext) InstallFile(installPath, srcPath string) {
322 var fullInstallPath string
323 if a.arch.HostOrDevice.Device() {
324 // TODO: replace unset with a device name once we have device targeting
325 fullInstallPath = filepath.Join("out/target/product/unset/system", installPath,
326 filepath.Base(srcPath))
327 } else {
328 // TODO: replace unset with a host name
329 fullInstallPath = filepath.Join("out/host/unset/", installPath, filepath.Base(srcPath))
330 }
331
332 a.ModuleContext.Build(pctx, blueprint.BuildParams{
333 Rule: Cp,
334 Outputs: []string{fullInstallPath},
335 Inputs: []string{srcPath},
336 OrderOnly: a.installDeps,
337 })
338
339 a.installFiles = append(a.installFiles, fullInstallPath)
Colin Cross3f40fa42015-01-30 17:27:36 -0800340}
341
342func (a *androidModuleContext) CheckbuildFile(srcPath string) {
343 a.checkbuildFiles = append(a.checkbuildFiles, srcPath)
344}
345
346type androidDynamicDependerContext struct {
347 blueprint.DynamicDependerModuleContext
348 module *AndroidModuleBase
349}
350
351type fileInstaller interface {
352 filesToInstall() []string
353}
354
355func isFileInstaller(m blueprint.Module) bool {
356 _, ok := m.(fileInstaller)
357 return ok
358}
359
360func isAndroidModule(m blueprint.Module) bool {
361 _, ok := m.(AndroidModule)
362 return ok
363}