blob: 2bbd452b12933ec6516988a1dfb598a833f55ca3 [file] [log] [blame]
Dan Willemsen218f6562015-07-08 18:13:11 -07001// 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
Colin Cross635c3b02016-05-18 15:37:25 -070015package android
Dan Willemsen218f6562015-07-08 18:13:11 -070016
17import (
18 "bytes"
Dan Willemsen97750522016-02-09 17:43:51 -080019 "fmt"
Dan Willemsen218f6562015-07-08 18:13:11 -070020 "io"
21 "io/ioutil"
22 "os"
23 "path/filepath"
24 "sort"
Dan Willemsen0fda89f2016-06-01 15:25:32 -070025 "strings"
Dan Willemsen218f6562015-07-08 18:13:11 -070026
Dan Willemsen218f6562015-07-08 18:13:11 -070027 "github.com/google/blueprint"
Colin Cross2465c3d2018-09-28 10:19:18 -070028 "github.com/google/blueprint/bootstrap"
Dan Willemsen218f6562015-07-08 18:13:11 -070029)
30
dimitry1f33e402019-03-26 12:39:31 +010031var (
32 NativeBridgeSuffix = ".native_bridge"
33)
34
Dan Willemsen218f6562015-07-08 18:13:11 -070035func init() {
Colin Cross798bfce2016-10-12 14:28:16 -070036 RegisterSingletonType("androidmk", AndroidMkSingleton)
Dan Willemsen218f6562015-07-08 18:13:11 -070037}
38
Jaewoong Jung9aa3ab12019-04-03 15:47:29 -070039// Deprecated: consider using AndroidMkEntriesProvider instead, especially if you're not going to
40// use the Custom function.
Dan Willemsen218f6562015-07-08 18:13:11 -070041type AndroidMkDataProvider interface {
Colin Crossa18e9cf2017-08-10 17:00:19 -070042 AndroidMk() AndroidMkData
Colin Crossce75d2c2016-10-06 16:12:58 -070043 BaseModuleName() string
Dan Willemsen218f6562015-07-08 18:13:11 -070044}
45
46type AndroidMkData struct {
Sasha Smundakb6d23052019-04-01 18:37:36 -070047 Class string
48 SubName string
49 DistFile OptionalPath
50 OutputFile OptionalPath
51 Disabled bool
52 Include string
53 Required []string
54 Host_required []string
55 Target_required []string
Dan Willemsen218f6562015-07-08 18:13:11 -070056
Colin Cross0f86d182017-08-10 17:07:28 -070057 Custom func(w io.Writer, name, prefix, moduleDir string, data AndroidMkData)
Dan Willemsen218f6562015-07-08 18:13:11 -070058
Colin Cross27a4b052017-08-10 16:32:23 -070059 Extra []AndroidMkExtraFunc
Colin Cross0f86d182017-08-10 17:07:28 -070060
61 preamble bytes.Buffer
Dan Willemsen218f6562015-07-08 18:13:11 -070062}
63
Colin Cross27a4b052017-08-10 16:32:23 -070064type AndroidMkExtraFunc func(w io.Writer, outputFile Path)
65
Jaewoong Jung9aa3ab12019-04-03 15:47:29 -070066// Allows modules to customize their Android*.mk output.
67type AndroidMkEntriesProvider interface {
68 AndroidMkEntries() AndroidMkEntries
69 BaseModuleName() string
70}
71
72type AndroidMkEntries struct {
73 Class string
74 SubName string
75 DistFile OptionalPath
76 OutputFile OptionalPath
77 Disabled bool
78 Include string
79 Required []string
80 Host_required []string
81 Target_required []string
82
83 header bytes.Buffer
84 footer bytes.Buffer
85
86 AddCustomEntries func(name, prefix, moduleDir string, entries *AndroidMkEntries)
87
88 EntryMap map[string][]string
89 entryOrder []string
90}
91
92func (a *AndroidMkEntries) SetString(name, value string) {
93 if _, ok := a.EntryMap[name]; !ok {
94 a.entryOrder = append(a.entryOrder, name)
95 }
96 a.EntryMap[name] = []string{value}
97}
98
99func (a *AndroidMkEntries) SetBoolIfTrue(name string, flag bool) {
100 if flag {
101 if _, ok := a.EntryMap[name]; !ok {
102 a.entryOrder = append(a.entryOrder, name)
103 }
104 a.EntryMap[name] = []string{"true"}
105 }
106}
107
108func (a *AndroidMkEntries) AddStrings(name string, value ...string) {
109 if len(value) == 0 {
110 return
111 }
112 if _, ok := a.EntryMap[name]; !ok {
113 a.entryOrder = append(a.entryOrder, name)
114 }
115 a.EntryMap[name] = append(a.EntryMap[name], value...)
116}
117
118func (a *AndroidMkEntries) fillInEntries(config Config, bpPath string, mod blueprint.Module) {
119 a.EntryMap = make(map[string][]string)
120 amod := mod.(Module).base()
121 name := amod.BaseModuleName()
122
123 if a.Include == "" {
124 a.Include = "$(BUILD_PREBUILT)"
125 }
126 a.Required = append(a.Required, amod.commonProperties.Required...)
127 a.Host_required = append(a.Host_required, amod.commonProperties.Host_required...)
128 a.Target_required = append(a.Target_required, amod.commonProperties.Target_required...)
129
130 // Fill in the header part.
131 if len(amod.commonProperties.Dist.Targets) > 0 {
132 distFile := a.DistFile
133 if !distFile.Valid() {
134 distFile = a.OutputFile
135 }
136 if distFile.Valid() {
137 dest := filepath.Base(distFile.String())
138
139 if amod.commonProperties.Dist.Dest != nil {
140 var err error
141 if dest, err = validateSafePath(*amod.commonProperties.Dist.Dest); err != nil {
142 // This was checked in ModuleBase.GenerateBuildActions
143 panic(err)
144 }
145 }
146
147 if amod.commonProperties.Dist.Suffix != nil {
148 ext := filepath.Ext(dest)
149 suffix := *amod.commonProperties.Dist.Suffix
150 dest = strings.TrimSuffix(dest, ext) + suffix + ext
151 }
152
153 if amod.commonProperties.Dist.Dir != nil {
154 var err error
155 if dest, err = validateSafePath(*amod.commonProperties.Dist.Dir, dest); err != nil {
156 // This was checked in ModuleBase.GenerateBuildActions
157 panic(err)
158 }
159 }
160
161 goals := strings.Join(amod.commonProperties.Dist.Targets, " ")
162 fmt.Fprintln(&a.header, ".PHONY:", goals)
163 fmt.Fprintf(&a.header, "$(call dist-for-goals,%s,%s:%s)\n",
164 goals, distFile.String(), dest)
165 }
166 }
167
dimitry1f33e402019-03-26 12:39:31 +0100168 if amod.Target().NativeBridge {
169 a.SubName += NativeBridgeSuffix
170 }
171
Jaewoong Jung9aa3ab12019-04-03 15:47:29 -0700172 fmt.Fprintln(&a.header, "\ninclude $(CLEAR_VARS)")
173
174 // Collect make variable assignment entries.
175 a.SetString("LOCAL_PATH", filepath.Dir(bpPath))
176 a.SetString("LOCAL_MODULE", name+a.SubName)
177 a.SetString("LOCAL_MODULE_CLASS", a.Class)
178 a.SetString("LOCAL_PREBUILT_MODULE_FILE", a.OutputFile.String())
179 a.AddStrings("LOCAL_REQUIRED_MODULES", a.Required...)
180 a.AddStrings("LOCAL_HOST_REQUIRED_MODULES", a.Host_required...)
181 a.AddStrings("LOCAL_TARGET_REQUIRED_MODULES", a.Target_required...)
182
183 archStr := amod.Arch().ArchType.String()
184 host := false
185 switch amod.Os().Class {
186 case Host:
187 // Make cannot identify LOCAL_MODULE_HOST_ARCH:= common.
188 if archStr != "common" {
189 a.SetString("LOCAL_MODULE_HOST_ARCH", archStr)
190 }
191 host = true
192 case HostCross:
193 // Make cannot identify LOCAL_MODULE_HOST_CROSS_ARCH:= common.
194 if archStr != "common" {
195 a.SetString("LOCAL_MODULE_HOST_CROSS_ARCH", archStr)
196 }
197 host = true
198 case Device:
199 // Make cannot identify LOCAL_MODULE_TARGET_ARCH:= common.
200 if archStr != "common" {
dimitry1f33e402019-03-26 12:39:31 +0100201 if amod.Target().NativeBridge {
202 // TODO: Unhardcode these rules.
203 guestArchStr := archStr
204 hostArchStr := ""
205 if guestArchStr == "arm" {
206 hostArchStr = "x86"
207 } else if guestArchStr == "arm64" {
208 hostArchStr = "x86_64"
209 }
210
211 if hostArchStr != "" {
212 a.SetString("LOCAL_MODULE_TARGET_ARCH", hostArchStr)
213 }
214 } else {
215 a.SetString("LOCAL_MODULE_TARGET_ARCH", archStr)
216 }
Jaewoong Jung9aa3ab12019-04-03 15:47:29 -0700217 }
218
219 a.AddStrings("LOCAL_INIT_RC", amod.commonProperties.Init_rc...)
220 a.AddStrings("LOCAL_VINTF_FRAGMENTS", amod.commonProperties.Vintf_fragments...)
221 a.SetBoolIfTrue("LOCAL_PROPRIETARY_MODULE", Bool(amod.commonProperties.Proprietary))
222 if Bool(amod.commonProperties.Vendor) || Bool(amod.commonProperties.Soc_specific) {
223 a.SetString("LOCAL_VENDOR_MODULE", "true")
224 }
225 a.SetBoolIfTrue("LOCAL_ODM_MODULE", Bool(amod.commonProperties.Device_specific))
226 a.SetBoolIfTrue("LOCAL_PRODUCT_MODULE", Bool(amod.commonProperties.Product_specific))
227 a.SetBoolIfTrue("LOCAL_PRODUCT_SERVICES_MODULE", Bool(amod.commonProperties.Product_services_specific))
228 if amod.commonProperties.Owner != nil {
229 a.SetString("LOCAL_MODULE_OWNER", *amod.commonProperties.Owner)
230 }
231 }
232
233 if amod.noticeFile.Valid() {
234 a.SetString("LOCAL_NOTICE_FILE", amod.noticeFile.String())
235 }
236
237 if host {
238 makeOs := amod.Os().String()
239 if amod.Os() == Linux || amod.Os() == LinuxBionic {
240 makeOs = "linux"
241 }
242 a.SetString("LOCAL_MODULE_HOST_OS", makeOs)
243 a.SetString("LOCAL_IS_HOST_MODULE", "true")
244 }
245
246 prefix := ""
247 if amod.ArchSpecific() {
248 switch amod.Os().Class {
249 case Host:
250 prefix = "HOST_"
251 case HostCross:
252 prefix = "HOST_CROSS_"
253 case Device:
254 prefix = "TARGET_"
255
256 }
257
258 if amod.Arch().ArchType != config.Targets[amod.Os()][0].Arch.ArchType {
259 prefix = "2ND_" + prefix
260 }
261 }
262 blueprintDir := filepath.Dir(bpPath)
263 if a.AddCustomEntries != nil {
264 a.AddCustomEntries(name, prefix, blueprintDir, a)
265 }
266
267 // Write to footer.
268 fmt.Fprintln(&a.footer, "include "+a.Include)
269}
270
271func (a *AndroidMkEntries) write(w io.Writer) {
272 w.Write(a.header.Bytes())
273 for _, name := range a.entryOrder {
274 fmt.Fprintln(w, name+" := "+strings.Join(a.EntryMap[name], " "))
275 }
276 w.Write(a.footer.Bytes())
277}
278
Colin Cross0875c522017-11-28 17:34:01 -0800279func AndroidMkSingleton() Singleton {
Dan Willemsen218f6562015-07-08 18:13:11 -0700280 return &androidMkSingleton{}
281}
282
283type androidMkSingleton struct{}
284
Colin Cross0875c522017-11-28 17:34:01 -0800285func (c *androidMkSingleton) GenerateBuildActions(ctx SingletonContext) {
Colin Crossaabf6792017-11-29 00:27:14 -0800286 if !ctx.Config().EmbeddedInMake() {
Dan Willemsen5ba07e82015-12-11 13:51:06 -0800287 return
288 }
289
Colin Cross2465c3d2018-09-28 10:19:18 -0700290 var androidMkModulesList []blueprint.Module
Colin Cross4f6e4e62016-01-11 12:55:55 -0800291
Colin Cross2465c3d2018-09-28 10:19:18 -0700292 ctx.VisitAllModulesBlueprint(func(module blueprint.Module) {
Colin Cross0875c522017-11-28 17:34:01 -0800293 androidMkModulesList = append(androidMkModulesList, module)
Colin Cross4f6e4e62016-01-11 12:55:55 -0800294 })
Dan Willemsen218f6562015-07-08 18:13:11 -0700295
Colin Cross1ad81422019-01-14 12:47:35 -0800296 sort.SliceStable(androidMkModulesList, func(i, j int) bool {
297 return ctx.ModuleName(androidMkModulesList[i]) < ctx.ModuleName(androidMkModulesList[j])
298 })
Colin Crossd779da42015-12-17 18:00:23 -0800299
Dan Willemsen45133ac2018-03-09 21:22:06 -0800300 transMk := PathForOutput(ctx, "Android"+String(ctx.Config().productVariables.Make_suffix)+".mk")
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700301 if ctx.Failed() {
302 return
303 }
Dan Willemsen218f6562015-07-08 18:13:11 -0700304
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700305 err := translateAndroidMk(ctx, transMk.String(), androidMkModulesList)
Dan Willemsen218f6562015-07-08 18:13:11 -0700306 if err != nil {
307 ctx.Errorf(err.Error())
308 }
309
Colin Cross0875c522017-11-28 17:34:01 -0800310 ctx.Build(pctx, BuildParams{
311 Rule: blueprint.Phony,
312 Output: transMk,
Dan Willemsen218f6562015-07-08 18:13:11 -0700313 })
314}
315
Colin Cross2465c3d2018-09-28 10:19:18 -0700316func translateAndroidMk(ctx SingletonContext, mkFile string, mods []blueprint.Module) error {
Dan Willemsen218f6562015-07-08 18:13:11 -0700317 buf := &bytes.Buffer{}
318
Dan Willemsen97750522016-02-09 17:43:51 -0800319 fmt.Fprintln(buf, "LOCAL_MODULE_MAKEFILE := $(lastword $(MAKEFILE_LIST))")
Dan Willemsen218f6562015-07-08 18:13:11 -0700320
Dan Willemsen70e17fa2016-07-25 16:00:20 -0700321 type_stats := make(map[string]int)
Dan Willemsen218f6562015-07-08 18:13:11 -0700322 for _, mod := range mods {
323 err := translateAndroidMkModule(ctx, buf, mod)
324 if err != nil {
325 os.Remove(mkFile)
326 return err
327 }
Dan Willemsen70e17fa2016-07-25 16:00:20 -0700328
Colin Cross2465c3d2018-09-28 10:19:18 -0700329 if amod, ok := mod.(Module); ok && ctx.PrimaryModule(amod) == amod {
330 type_stats[ctx.ModuleType(amod)] += 1
Dan Willemsen70e17fa2016-07-25 16:00:20 -0700331 }
332 }
333
334 keys := []string{}
335 fmt.Fprintln(buf, "\nSTATS.SOONG_MODULE_TYPE :=")
336 for k := range type_stats {
337 keys = append(keys, k)
338 }
339 sort.Strings(keys)
340 for _, mod_type := range keys {
341 fmt.Fprintln(buf, "STATS.SOONG_MODULE_TYPE +=", mod_type)
342 fmt.Fprintf(buf, "STATS.SOONG_MODULE_TYPE.%s := %d\n", mod_type, type_stats[mod_type])
Dan Willemsen218f6562015-07-08 18:13:11 -0700343 }
344
345 // Don't write to the file if it hasn't changed
346 if _, err := os.Stat(mkFile); !os.IsNotExist(err) {
347 if data, err := ioutil.ReadFile(mkFile); err == nil {
348 matches := buf.Len() == len(data)
349
350 if matches {
351 for i, value := range buf.Bytes() {
352 if value != data[i] {
353 matches = false
354 break
355 }
356 }
357 }
358
359 if matches {
360 return nil
361 }
362 }
363 }
364
365 return ioutil.WriteFile(mkFile, buf.Bytes(), 0666)
366}
367
Colin Cross0875c522017-11-28 17:34:01 -0800368func translateAndroidMkModule(ctx SingletonContext, w io.Writer, mod blueprint.Module) error {
Colin Cross953d3a22018-09-05 16:23:54 -0700369 defer func() {
370 if r := recover(); r != nil {
371 panic(fmt.Errorf("%s in translateAndroidMkModule for module %s variant %s",
372 r, ctx.ModuleName(mod), ctx.ModuleSubDir(mod)))
373 }
374 }()
375
Colin Cross2465c3d2018-09-28 10:19:18 -0700376 switch x := mod.(type) {
377 case AndroidMkDataProvider:
378 return translateAndroidModule(ctx, w, mod, x)
379 case bootstrap.GoBinaryTool:
380 return translateGoBinaryModule(ctx, w, mod, x)
Jaewoong Jung9aa3ab12019-04-03 15:47:29 -0700381 case AndroidMkEntriesProvider:
382 return translateAndroidMkEntriesModule(ctx, w, mod, x)
Colin Cross2465c3d2018-09-28 10:19:18 -0700383 default:
Dan Willemsen218f6562015-07-08 18:13:11 -0700384 return nil
385 }
Colin Cross2465c3d2018-09-28 10:19:18 -0700386}
387
388func translateGoBinaryModule(ctx SingletonContext, w io.Writer, mod blueprint.Module,
389 goBinary bootstrap.GoBinaryTool) error {
390
391 name := ctx.ModuleName(mod)
392 fmt.Fprintln(w, ".PHONY:", name)
393 fmt.Fprintln(w, name+":", goBinary.InstallPath())
394 fmt.Fprintln(w, "")
395
396 return nil
397}
398
399func translateAndroidModule(ctx SingletonContext, w io.Writer, mod blueprint.Module,
400 provider AndroidMkDataProvider) error {
Dan Willemsen218f6562015-07-08 18:13:11 -0700401
Colin Cross635c3b02016-05-18 15:37:25 -0700402 amod := mod.(Module).base()
Jaewoong Jung9aa3ab12019-04-03 15:47:29 -0700403 if shouldSkipAndroidMkProcessing(amod) {
Jeff Gaston088e29e2017-11-29 16:47:17 -0800404 return nil
405 }
406
Colin Cross91825d22017-08-10 16:59:47 -0700407 data := provider.AndroidMk()
Colin Cross53499412017-09-07 13:20:25 -0700408 if data.Include == "" {
409 data.Include = "$(BUILD_PREBUILT)"
410 }
411
Jaewoong Jung9aa3ab12019-04-03 15:47:29 -0700412 // Get the preamble content through AndroidMkEntries logic.
413 entries := AndroidMkEntries{
414 Class: data.Class,
415 SubName: data.SubName,
416 DistFile: data.DistFile,
417 OutputFile: data.OutputFile,
418 Disabled: data.Disabled,
419 Include: data.Include,
420 Required: data.Required,
421 Host_required: data.Host_required,
422 Target_required: data.Target_required,
Dan Willemsen01a405a2016-06-13 17:19:03 -0700423 }
Jaewoong Jung9aa3ab12019-04-03 15:47:29 -0700424 entries.fillInEntries(ctx.Config(), ctx.BlueprintFile(mod), mod)
425 // preamble doesn't need the footer content.
426 entries.footer = bytes.Buffer{}
427 entries.write(&data.preamble)
Dan Willemsen01a405a2016-06-13 17:19:03 -0700428
Colin Cross0f86d182017-08-10 17:07:28 -0700429 prefix := ""
430 if amod.ArchSpecific() {
431 switch amod.Os().Class {
432 case Host:
433 prefix = "HOST_"
434 case HostCross:
435 prefix = "HOST_CROSS_"
436 case Device:
437 prefix = "TARGET_"
Colin Crossa2344662016-03-24 13:14:12 -0700438
Dan Willemsen218f6562015-07-08 18:13:11 -0700439 }
440
Dan Willemsen0ef639b2018-10-10 17:02:29 -0700441 if amod.Arch().ArchType != ctx.Config().Targets[amod.Os()][0].Arch.ArchType {
Colin Cross0f86d182017-08-10 17:07:28 -0700442 prefix = "2ND_" + prefix
443 }
Dan Willemsen218f6562015-07-08 18:13:11 -0700444 }
445
Jaewoong Jung9aa3ab12019-04-03 15:47:29 -0700446 name := provider.BaseModuleName()
Colin Cross0f86d182017-08-10 17:07:28 -0700447 blueprintDir := filepath.Dir(ctx.BlueprintFile(mod))
448
449 if data.Custom != nil {
450 data.Custom(w, name, prefix, blueprintDir, data)
451 } else {
452 WriteAndroidMkData(w, data)
453 }
454
455 return nil
456}
457
458func WriteAndroidMkData(w io.Writer, data AndroidMkData) {
459 if data.Disabled {
460 return
461 }
462
463 if !data.OutputFile.Valid() {
464 return
465 }
466
467 w.Write(data.preamble.Bytes())
468
Colin Crossca860ac2016-01-04 14:34:37 -0800469 for _, extra := range data.Extra {
Colin Cross27a4b052017-08-10 16:32:23 -0700470 extra(w, data.OutputFile.Path())
Dan Willemsen97750522016-02-09 17:43:51 -0800471 }
472
Colin Cross53499412017-09-07 13:20:25 -0700473 fmt.Fprintln(w, "include "+data.Include)
Dan Willemsen218f6562015-07-08 18:13:11 -0700474}
Sasha Smundakb6d23052019-04-01 18:37:36 -0700475
Jaewoong Jung9aa3ab12019-04-03 15:47:29 -0700476func translateAndroidMkEntriesModule(ctx SingletonContext, w io.Writer, mod blueprint.Module,
477 provider AndroidMkEntriesProvider) error {
478 if shouldSkipAndroidMkProcessing(mod.(Module).base()) {
479 return nil
Sasha Smundakb6d23052019-04-01 18:37:36 -0700480 }
Jaewoong Jung9aa3ab12019-04-03 15:47:29 -0700481
482 entries := provider.AndroidMkEntries()
483 entries.fillInEntries(ctx.Config(), ctx.BlueprintFile(mod), mod)
484
485 entries.write(w)
486
487 return nil
488}
489
490func shouldSkipAndroidMkProcessing(module *ModuleBase) bool {
491 if !module.commonProperties.NamespaceExportedToMake {
492 // TODO(jeffrygaston) do we want to validate that there are no modules being
493 // exported to Kati that depend on this module?
494 return true
Sasha Smundakb6d23052019-04-01 18:37:36 -0700495 }
Jaewoong Jung9aa3ab12019-04-03 15:47:29 -0700496
497 return !module.Enabled() ||
498 module.commonProperties.SkipInstall ||
499 // Make does not understand LinuxBionic
500 module.Os() == LinuxBionic
Sasha Smundakb6d23052019-04-01 18:37:36 -0700501}