blob: 4b1200d3c89f693bdd8c18f1df3c3984ff383e58 [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 (
Colin Cross3f40fa42015-01-30 17:27:36 -080018 "path/filepath"
Colin Crossf6566ed2015-03-24 11:13:38 -070019
20 "github.com/google/blueprint"
Colin Cross3f40fa42015-01-30 17:27:36 -080021)
22
23var (
24 DeviceSharedLibrary = "shared_library"
25 DeviceStaticLibrary = "static_library"
26 DeviceExecutable = "executable"
27 HostSharedLibrary = "host_shared_library"
28 HostStaticLibrary = "host_static_library"
29 HostExecutable = "host_executable"
30)
31
Colin Crossf6566ed2015-03-24 11:13:38 -070032type androidBaseContext interface {
33 Arch() Arch
34 Host() bool
35 Device() bool
36 Debug() bool
37}
38
39type AndroidBaseContext interface {
40 blueprint.BaseModuleContext
41 androidBaseContext
42}
43
Colin Cross3f40fa42015-01-30 17:27:36 -080044type AndroidModuleContext interface {
45 blueprint.ModuleContext
Colin Crossf6566ed2015-03-24 11:13:38 -070046 androidBaseContext
Colin Cross3f40fa42015-01-30 17:27:36 -080047
Colin Cross3f40fa42015-01-30 17:27:36 -080048 InstallFile(installPath, srcPath string)
49 CheckbuildFile(srcPath string)
50}
51
52type AndroidModule interface {
53 blueprint.Module
54
55 GenerateAndroidBuildActions(AndroidModuleContext)
56
57 base() *AndroidModuleBase
58 Disabled() bool
59 HostOrDevice() HostOrDevice
60}
61
62type AndroidDynamicDepender interface {
63 AndroidDynamicDependencies(ctx AndroidDynamicDependerModuleContext) []string
64}
65
66type AndroidDynamicDependerModuleContext interface {
67 blueprint.DynamicDependerModuleContext
Colin Crossf6566ed2015-03-24 11:13:38 -070068 androidBaseContext
Colin Cross3f40fa42015-01-30 17:27:36 -080069}
70
71type commonProperties struct {
72 Name string
73 Deps []string
74 ResourceDirs []string
75
76 // disabled: don't emit any build rules for this module
77 Disabled bool `android:"arch_variant"`
78
79 // multilib: control whether this module compiles for 32-bit, 64-bit, or both. Possible values
80 // are "32" (compile for 32-bit only), "64" (compile for 64-bit only), "both" (compile for both
81 // architectures), or "first" (compile for 64-bit on a 64-bit platform, and 32-bit on a 32-bit
82 // platform
83 Compile_multilib string
84
85 // Set by ArchMutator
86 CompileArch Arch `blueprint:"mutated"`
87
88 // Set by InitAndroidModule
89 HostOrDeviceSupported HostOrDeviceSupported `blueprint:"mutated"`
90}
91
92type hostAndDeviceProperties struct {
93 Host_supported bool
94 Device_supported bool
95}
96
Colin Crossc472d572015-03-17 15:06:21 -070097type Multilib string
98
99const (
100 MultilibBoth Multilib = "both"
101 MultilibFirst Multilib = "first"
102)
103
Colin Cross5049f022015-03-18 13:28:46 -0700104func InitAndroidModule(m AndroidModule,
Colin Cross3f40fa42015-01-30 17:27:36 -0800105 propertyStructs ...interface{}) (blueprint.Module, []interface{}) {
106
107 base := m.base()
108 base.module = m
Colin Cross5049f022015-03-18 13:28:46 -0700109
110 propertyStructs = append(propertyStructs, &base.commonProperties)
111
112 return m, propertyStructs
113}
114
115func InitAndroidArchModule(m AndroidModule, hod HostOrDeviceSupported, defaultMultilib Multilib,
116 propertyStructs ...interface{}) (blueprint.Module, []interface{}) {
117
118 _, propertyStructs = InitAndroidModule(m, propertyStructs...)
119
120 base := m.base()
Colin Cross3f40fa42015-01-30 17:27:36 -0800121 base.commonProperties.HostOrDeviceSupported = hod
122
123 if hod == HostAndDeviceSupported {
124 // Default to module to device supported, host not supported, can override in module
125 // properties
126 base.hostAndDeviceProperties.Device_supported = true
127 propertyStructs = append(propertyStructs, &base.hostAndDeviceProperties)
128 }
129
130 return InitArchModule(m, defaultMultilib, propertyStructs...)
131}
132
133// A AndroidModuleBase object contains the properties that are common to all Android
134// modules. It should be included as an anonymous field in every module
135// struct definition. InitAndroidModule should then be called from the module's
136// factory function, and the return values from InitAndroidModule should be
137// returned from the factory function.
138//
139// The AndroidModuleBase type is responsible for implementing the
140// GenerateBuildActions method to support the blueprint.Module interface. This
141// method will then call the module's GenerateAndroidBuildActions method once
142// for each build variant that is to be built. GenerateAndroidBuildActions is
143// passed a AndroidModuleContext rather than the usual blueprint.ModuleContext.
144// AndroidModuleContext exposes extra functionality specific to the Android build
145// system including details about the particular build variant that is to be
146// generated.
147//
148// For example:
149//
150// import (
151// "android/soong/common"
Colin Cross70b40592015-03-23 12:57:34 -0700152// "github.com/google/blueprint"
Colin Cross3f40fa42015-01-30 17:27:36 -0800153// )
154//
155// type myModule struct {
156// common.AndroidModuleBase
157// properties struct {
158// MyProperty string
159// }
160// }
161//
162// func NewMyModule() (blueprint.Module, []interface{}) {
163// m := &myModule{}
164// return common.InitAndroidModule(m, &m.properties)
165// }
166//
167// func (m *myModule) GenerateAndroidBuildActions(ctx common.AndroidModuleContext) {
168// // Get the CPU architecture for the current build variant.
169// variantArch := ctx.Arch()
170//
171// // ...
172// }
173type AndroidModuleBase struct {
174 // Putting the curiously recurring thing pointing to the thing that contains
175 // the thing pattern to good use.
176 module AndroidModule
177
178 commonProperties commonProperties
179 hostAndDeviceProperties hostAndDeviceProperties
180 generalProperties []interface{}
181 archProperties []*archProperties
182
183 noAddressSanitizer bool
184 installFiles []string
185 checkbuildFiles []string
186}
187
188func (a *AndroidModuleBase) base() *AndroidModuleBase {
189 return a
190}
191
192func (a *AndroidModuleBase) SetArch(arch Arch) {
193 a.commonProperties.CompileArch = arch
194}
195
196func (a *AndroidModuleBase) HostOrDevice() HostOrDevice {
197 return a.commonProperties.CompileArch.HostOrDevice
198}
199
200func (a *AndroidModuleBase) HostSupported() bool {
201 return a.commonProperties.HostOrDeviceSupported == HostSupported ||
202 a.commonProperties.HostOrDeviceSupported == HostAndDeviceSupported &&
203 a.hostAndDeviceProperties.Host_supported
204}
205
206func (a *AndroidModuleBase) DeviceSupported() bool {
207 return a.commonProperties.HostOrDeviceSupported == DeviceSupported ||
208 a.commonProperties.HostOrDeviceSupported == HostAndDeviceSupported &&
209 a.hostAndDeviceProperties.Device_supported
210}
211
212func (a *AndroidModuleBase) Disabled() bool {
213 return a.commonProperties.Disabled
214}
215
216func (a *AndroidModuleBase) computeInstallDeps(
217 ctx blueprint.ModuleContext) []string {
218
219 result := []string{}
220 ctx.VisitDepsDepthFirstIf(isFileInstaller,
221 func(m blueprint.Module) {
222 fileInstaller := m.(fileInstaller)
223 files := fileInstaller.filesToInstall()
224 result = append(result, files...)
225 })
226
227 return result
228}
229
230func (a *AndroidModuleBase) filesToInstall() []string {
231 return a.installFiles
232}
233
234func (p *AndroidModuleBase) NoAddressSanitizer() bool {
235 return p.noAddressSanitizer
236}
237
238func (p *AndroidModuleBase) resourceDirs() []string {
239 return p.commonProperties.ResourceDirs
240}
241
242func (a *AndroidModuleBase) generateModuleTarget(ctx blueprint.ModuleContext) {
243 if a != ctx.FinalModule().(AndroidModule).base() {
244 return
245 }
246
247 allInstalledFiles := []string{}
Colin Cross9454bfa2015-03-17 13:24:18 -0700248 allCheckbuildFiles := []string{}
Colin Cross3f40fa42015-01-30 17:27:36 -0800249 ctx.VisitAllModuleVariants(func(module blueprint.Module) {
250 if androidModule, ok := module.(AndroidModule); ok {
251 files := androidModule.base().installFiles
252 allInstalledFiles = append(allInstalledFiles, files...)
Colin Cross9454bfa2015-03-17 13:24:18 -0700253 files = androidModule.base().checkbuildFiles
254 allCheckbuildFiles = append(allCheckbuildFiles, files...)
Colin Cross3f40fa42015-01-30 17:27:36 -0800255 }
256 })
257
Colin Cross9454bfa2015-03-17 13:24:18 -0700258 deps := []string{}
259
Colin Cross3f40fa42015-01-30 17:27:36 -0800260 if len(allInstalledFiles) > 0 {
Colin Cross9454bfa2015-03-17 13:24:18 -0700261 name := ctx.ModuleName() + "-install"
Colin Cross3f40fa42015-01-30 17:27:36 -0800262 ctx.Build(pctx, blueprint.BuildParams{
Colin Cross9454bfa2015-03-17 13:24:18 -0700263 Rule: blueprint.Phony,
264 Outputs: []string{name},
265 Implicits: allInstalledFiles,
266 })
267 deps = append(deps, name)
268 }
269
270 if len(allCheckbuildFiles) > 0 {
271 name := ctx.ModuleName() + "-checkbuild"
272 ctx.Build(pctx, blueprint.BuildParams{
273 Rule: blueprint.Phony,
274 Outputs: []string{name},
275 Implicits: allCheckbuildFiles,
276 Optional: true,
277 })
278 deps = append(deps, name)
279 }
280
281 if len(deps) > 0 {
282 ctx.Build(pctx, blueprint.BuildParams{
283 Rule: blueprint.Phony,
284 Outputs: []string{ctx.ModuleName()},
285 Implicits: deps,
286 Optional: true,
Colin Cross3f40fa42015-01-30 17:27:36 -0800287 })
288 }
289}
290
291func (a *AndroidModuleBase) DynamicDependencies(ctx blueprint.DynamicDependerModuleContext) []string {
292 actx := &androidDynamicDependerContext{
293 DynamicDependerModuleContext: ctx,
Colin Crossf6566ed2015-03-24 11:13:38 -0700294 androidBaseContextImpl: androidBaseContextImpl{
295 arch: a.commonProperties.CompileArch,
296 },
Colin Cross3f40fa42015-01-30 17:27:36 -0800297 }
298
299 if dynamic, ok := a.module.(AndroidDynamicDepender); ok {
300 return dynamic.AndroidDynamicDependencies(actx)
301 }
302
303 return nil
304}
305
306func (a *AndroidModuleBase) GenerateBuildActions(ctx blueprint.ModuleContext) {
307 androidCtx := &androidModuleContext{
308 ModuleContext: ctx,
Colin Crossf6566ed2015-03-24 11:13:38 -0700309 androidBaseContextImpl: androidBaseContextImpl{
310 arch: a.commonProperties.CompileArch,
311 },
312 installDeps: a.computeInstallDeps(ctx),
313 installFiles: a.installFiles,
Colin Cross3f40fa42015-01-30 17:27:36 -0800314 }
315
316 if a.commonProperties.Disabled {
317 return
318 }
319
320 a.module.GenerateAndroidBuildActions(androidCtx)
321 if ctx.Failed() {
322 return
323 }
324
325 a.generateModuleTarget(ctx)
326 if ctx.Failed() {
327 return
328 }
Colin Cross9454bfa2015-03-17 13:24:18 -0700329
330 a.installFiles = append(a.installFiles, androidCtx.installFiles...)
331 a.checkbuildFiles = append(a.checkbuildFiles, androidCtx.checkbuildFiles...)
Colin Cross3f40fa42015-01-30 17:27:36 -0800332}
333
Colin Crossf6566ed2015-03-24 11:13:38 -0700334type androidBaseContextImpl struct {
335 arch Arch
336 debug bool
337}
338
Colin Cross3f40fa42015-01-30 17:27:36 -0800339type androidModuleContext struct {
340 blueprint.ModuleContext
Colin Crossf6566ed2015-03-24 11:13:38 -0700341 androidBaseContextImpl
Colin Cross3f40fa42015-01-30 17:27:36 -0800342 installDeps []string
343 installFiles []string
344 checkbuildFiles []string
345}
346
347func (a *androidModuleContext) Build(pctx *blueprint.PackageContext, params blueprint.BuildParams) {
348 params.Optional = true
349 a.ModuleContext.Build(pctx, params)
350}
351
Colin Crossf6566ed2015-03-24 11:13:38 -0700352func (a *androidBaseContextImpl) Arch() Arch {
Colin Cross3f40fa42015-01-30 17:27:36 -0800353 return a.arch
354}
355
Colin Crossf6566ed2015-03-24 11:13:38 -0700356func (a *androidBaseContextImpl) Host() bool {
357 return a.arch.HostOrDevice.Host()
358}
359
360func (a *androidBaseContextImpl) Device() bool {
361 return a.arch.HostOrDevice.Device()
362}
363
364func (a *androidBaseContextImpl) Debug() bool {
365 return a.debug
366}
367
Colin Cross3f40fa42015-01-30 17:27:36 -0800368func (a *androidModuleContext) InstallFile(installPath, srcPath string) {
369 var fullInstallPath string
370 if a.arch.HostOrDevice.Device() {
371 // TODO: replace unset with a device name once we have device targeting
372 fullInstallPath = filepath.Join("out/target/product/unset/system", installPath,
373 filepath.Base(srcPath))
374 } else {
375 // TODO: replace unset with a host name
376 fullInstallPath = filepath.Join("out/host/unset/", installPath, filepath.Base(srcPath))
377 }
378
379 a.ModuleContext.Build(pctx, blueprint.BuildParams{
380 Rule: Cp,
381 Outputs: []string{fullInstallPath},
382 Inputs: []string{srcPath},
383 OrderOnly: a.installDeps,
384 })
385
386 a.installFiles = append(a.installFiles, fullInstallPath)
Colin Cross3f40fa42015-01-30 17:27:36 -0800387}
388
389func (a *androidModuleContext) CheckbuildFile(srcPath string) {
390 a.checkbuildFiles = append(a.checkbuildFiles, srcPath)
391}
392
393type androidDynamicDependerContext struct {
394 blueprint.DynamicDependerModuleContext
Colin Crossf6566ed2015-03-24 11:13:38 -0700395 androidBaseContextImpl
Colin Cross3f40fa42015-01-30 17:27:36 -0800396}
397
398type fileInstaller interface {
399 filesToInstall() []string
400}
401
402func isFileInstaller(m blueprint.Module) bool {
403 _, ok := m.(fileInstaller)
404 return ok
405}
406
407func isAndroidModule(m blueprint.Module) bool {
408 _, ok := m.(AndroidModule)
409 return ok
410}