blob: 4a968f5ebeb8508a91cfcdde93381062e55c1fa6 [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
31func init() {
Colin Cross798bfce2016-10-12 14:28:16 -070032 RegisterSingletonType("androidmk", AndroidMkSingleton)
Dan Willemsen218f6562015-07-08 18:13:11 -070033}
34
Jaewoong Jung87a94c02019-04-03 15:47:29 -070035// Deprecated: consider using AndroidMkEntriesProvider instead, especially if you're not going to
36// use the Custom function.
Dan Willemsen218f6562015-07-08 18:13:11 -070037type AndroidMkDataProvider interface {
Colin Crossa18e9cf2017-08-10 17:00:19 -070038 AndroidMk() AndroidMkData
Colin Crossce75d2c2016-10-06 16:12:58 -070039 BaseModuleName() string
Dan Willemsen218f6562015-07-08 18:13:11 -070040}
41
42type AndroidMkData struct {
43 Class string
Colin Crossa2344662016-03-24 13:14:12 -070044 SubName string
Dan Willemsen569edc52018-11-19 09:33:29 -080045 DistFile OptionalPath
Dan Willemsen34cc69e2015-09-23 15:26:20 -070046 OutputFile OptionalPath
Colin Crossca860ac2016-01-04 14:34:37 -080047 Disabled bool
Colin Cross53499412017-09-07 13:20:25 -070048 Include string
Colin Cross92430102017-10-09 14:59:32 -070049 Required []string
Dan Willemsen218f6562015-07-08 18:13:11 -070050
Colin Cross0f86d182017-08-10 17:07:28 -070051 Custom func(w io.Writer, name, prefix, moduleDir string, data AndroidMkData)
Dan Willemsen218f6562015-07-08 18:13:11 -070052
Colin Cross27a4b052017-08-10 16:32:23 -070053 Extra []AndroidMkExtraFunc
Colin Cross0f86d182017-08-10 17:07:28 -070054
55 preamble bytes.Buffer
Dan Willemsen218f6562015-07-08 18:13:11 -070056}
57
Colin Cross27a4b052017-08-10 16:32:23 -070058type AndroidMkExtraFunc func(w io.Writer, outputFile Path)
59
Jaewoong Jung87a94c02019-04-03 15:47:29 -070060// Allows modules to customize their Android*.mk output.
61type AndroidMkEntriesProvider interface {
62 AndroidMkEntries() AndroidMkEntries
63 BaseModuleName() string
64}
65
66type AndroidMkEntries struct {
67 Class string
68 SubName string
69 DistFile OptionalPath
70 OutputFile OptionalPath
71 Disabled bool
72 Include string
73 Required []string
74
75 header bytes.Buffer
76 footer bytes.Buffer
77
Jaewoong Jung283a9ee2019-08-27 17:33:16 -070078 ExtraEntries []AndroidMkExtraEntriesFunc
Jaewoong Jung87a94c02019-04-03 15:47:29 -070079
80 EntryMap map[string][]string
81 entryOrder []string
82}
83
Jaewoong Jung283a9ee2019-08-27 17:33:16 -070084type AndroidMkExtraEntriesFunc func(entries *AndroidMkEntries)
85
Jaewoong Jung87a94c02019-04-03 15:47:29 -070086func (a *AndroidMkEntries) SetString(name, value string) {
87 if _, ok := a.EntryMap[name]; !ok {
88 a.entryOrder = append(a.entryOrder, name)
89 }
90 a.EntryMap[name] = []string{value}
91}
92
93func (a *AndroidMkEntries) SetBoolIfTrue(name string, flag bool) {
94 if flag {
95 if _, ok := a.EntryMap[name]; !ok {
96 a.entryOrder = append(a.entryOrder, name)
97 }
98 a.EntryMap[name] = []string{"true"}
99 }
100}
101
102func (a *AndroidMkEntries) AddStrings(name string, value ...string) {
103 if len(value) == 0 {
104 return
105 }
106 if _, ok := a.EntryMap[name]; !ok {
107 a.entryOrder = append(a.entryOrder, name)
108 }
109 a.EntryMap[name] = append(a.EntryMap[name], value...)
110}
111
112func (a *AndroidMkEntries) fillInEntries(config Config, bpPath string, mod blueprint.Module) {
113 a.EntryMap = make(map[string][]string)
114 amod := mod.(Module).base()
115 name := amod.BaseModuleName()
116
117 if a.Include == "" {
118 a.Include = "$(BUILD_PREBUILT)"
119 }
120 a.Required = append(a.Required, amod.commonProperties.Required...)
121
122 // Fill in the header part.
123 if len(amod.commonProperties.Dist.Targets) > 0 {
124 distFile := a.DistFile
125 if !distFile.Valid() {
126 distFile = a.OutputFile
127 }
128 if distFile.Valid() {
129 dest := filepath.Base(distFile.String())
130
131 if amod.commonProperties.Dist.Dest != nil {
132 var err error
133 if dest, err = validateSafePath(*amod.commonProperties.Dist.Dest); err != nil {
134 // This was checked in ModuleBase.GenerateBuildActions
135 panic(err)
136 }
137 }
138
139 if amod.commonProperties.Dist.Suffix != nil {
140 ext := filepath.Ext(dest)
141 suffix := *amod.commonProperties.Dist.Suffix
142 dest = strings.TrimSuffix(dest, ext) + suffix + ext
143 }
144
145 if amod.commonProperties.Dist.Dir != nil {
146 var err error
147 if dest, err = validateSafePath(*amod.commonProperties.Dist.Dir, dest); err != nil {
148 // This was checked in ModuleBase.GenerateBuildActions
149 panic(err)
150 }
151 }
152
153 goals := strings.Join(amod.commonProperties.Dist.Targets, " ")
154 fmt.Fprintln(&a.header, ".PHONY:", goals)
155 fmt.Fprintf(&a.header, "$(call dist-for-goals,%s,%s:%s)\n",
156 goals, distFile.String(), dest)
157 }
158 }
159
160 fmt.Fprintln(&a.header, "\ninclude $(CLEAR_VARS)")
161
162 // Collect make variable assignment entries.
163 a.SetString("LOCAL_PATH", filepath.Dir(bpPath))
164 a.SetString("LOCAL_MODULE", name+a.SubName)
165 a.SetString("LOCAL_MODULE_CLASS", a.Class)
166 a.SetString("LOCAL_PREBUILT_MODULE_FILE", a.OutputFile.String())
167 a.AddStrings("LOCAL_REQUIRED_MODULES", a.Required...)
168
169 archStr := amod.Arch().ArchType.String()
170 host := false
171 switch amod.Os().Class {
172 case Host:
173 // Make cannot identify LOCAL_MODULE_HOST_ARCH:= common.
174 if archStr != "common" {
175 a.SetString("LOCAL_MODULE_HOST_ARCH", archStr)
176 }
177 host = true
178 case HostCross:
179 // Make cannot identify LOCAL_MODULE_HOST_CROSS_ARCH:= common.
180 if archStr != "common" {
181 a.SetString("LOCAL_MODULE_HOST_CROSS_ARCH", archStr)
182 }
183 host = true
184 case Device:
185 // Make cannot identify LOCAL_MODULE_TARGET_ARCH:= common.
186 if archStr != "common" {
187 a.SetString("LOCAL_MODULE_TARGET_ARCH", archStr)
188 }
189
190 a.AddStrings("LOCAL_INIT_RC", amod.commonProperties.Init_rc...)
191 a.AddStrings("LOCAL_VINTF_FRAGMENTS", amod.commonProperties.Vintf_fragments...)
192 a.SetBoolIfTrue("LOCAL_PROPRIETARY_MODULE", Bool(amod.commonProperties.Proprietary))
193 if Bool(amod.commonProperties.Vendor) || Bool(amod.commonProperties.Soc_specific) {
194 a.SetString("LOCAL_VENDOR_MODULE", "true")
195 }
196 a.SetBoolIfTrue("LOCAL_ODM_MODULE", Bool(amod.commonProperties.Device_specific))
197 a.SetBoolIfTrue("LOCAL_PRODUCT_MODULE", Bool(amod.commonProperties.Product_specific))
198 a.SetBoolIfTrue("LOCAL_PRODUCT_SERVICES_MODULE", Bool(amod.commonProperties.Product_services_specific))
199 if amod.commonProperties.Owner != nil {
200 a.SetString("LOCAL_MODULE_OWNER", *amod.commonProperties.Owner)
201 }
202 }
203
204 if amod.noticeFile.Valid() {
205 a.SetString("LOCAL_NOTICE_FILE", amod.noticeFile.String())
206 }
207
208 if host {
209 makeOs := amod.Os().String()
210 if amod.Os() == Linux || amod.Os() == LinuxBionic {
211 makeOs = "linux"
212 }
213 a.SetString("LOCAL_MODULE_HOST_OS", makeOs)
214 a.SetString("LOCAL_IS_HOST_MODULE", "true")
215 }
216
217 prefix := ""
218 if amod.ArchSpecific() {
219 switch amod.Os().Class {
220 case Host:
221 prefix = "HOST_"
222 case HostCross:
223 prefix = "HOST_CROSS_"
224 case Device:
225 prefix = "TARGET_"
226
227 }
228
229 if amod.Arch().ArchType != config.Targets[amod.Os()][0].Arch.ArchType {
230 prefix = "2ND_" + prefix
231 }
232 }
Jaewoong Jung283a9ee2019-08-27 17:33:16 -0700233 for _, extra := range a.ExtraEntries {
234 extra(a)
Jaewoong Jung87a94c02019-04-03 15:47:29 -0700235 }
236
237 // Write to footer.
238 fmt.Fprintln(&a.footer, "include "+a.Include)
239}
240
241func (a *AndroidMkEntries) write(w io.Writer) {
242 w.Write(a.header.Bytes())
243 for _, name := range a.entryOrder {
244 fmt.Fprintln(w, name+" := "+strings.Join(a.EntryMap[name], " "))
245 }
246 w.Write(a.footer.Bytes())
247}
248
Colin Cross0875c522017-11-28 17:34:01 -0800249func AndroidMkSingleton() Singleton {
Dan Willemsen218f6562015-07-08 18:13:11 -0700250 return &androidMkSingleton{}
251}
252
253type androidMkSingleton struct{}
254
Colin Cross0875c522017-11-28 17:34:01 -0800255func (c *androidMkSingleton) GenerateBuildActions(ctx SingletonContext) {
Colin Crossaabf6792017-11-29 00:27:14 -0800256 if !ctx.Config().EmbeddedInMake() {
Dan Willemsen5ba07e82015-12-11 13:51:06 -0800257 return
258 }
259
Colin Cross2465c3d2018-09-28 10:19:18 -0700260 var androidMkModulesList []blueprint.Module
Colin Cross4f6e4e62016-01-11 12:55:55 -0800261
Colin Cross2465c3d2018-09-28 10:19:18 -0700262 ctx.VisitAllModulesBlueprint(func(module blueprint.Module) {
Colin Cross0875c522017-11-28 17:34:01 -0800263 androidMkModulesList = append(androidMkModulesList, module)
Colin Cross4f6e4e62016-01-11 12:55:55 -0800264 })
Dan Willemsen218f6562015-07-08 18:13:11 -0700265
Colin Cross1ad81422019-01-14 12:47:35 -0800266 sort.SliceStable(androidMkModulesList, func(i, j int) bool {
267 return ctx.ModuleName(androidMkModulesList[i]) < ctx.ModuleName(androidMkModulesList[j])
268 })
Colin Crossd779da42015-12-17 18:00:23 -0800269
Dan Willemsen45133ac2018-03-09 21:22:06 -0800270 transMk := PathForOutput(ctx, "Android"+String(ctx.Config().productVariables.Make_suffix)+".mk")
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700271 if ctx.Failed() {
272 return
273 }
Dan Willemsen218f6562015-07-08 18:13:11 -0700274
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700275 err := translateAndroidMk(ctx, transMk.String(), androidMkModulesList)
Dan Willemsen218f6562015-07-08 18:13:11 -0700276 if err != nil {
277 ctx.Errorf(err.Error())
278 }
279
Colin Cross0875c522017-11-28 17:34:01 -0800280 ctx.Build(pctx, BuildParams{
281 Rule: blueprint.Phony,
282 Output: transMk,
Dan Willemsen218f6562015-07-08 18:13:11 -0700283 })
284}
285
Colin Cross2465c3d2018-09-28 10:19:18 -0700286func translateAndroidMk(ctx SingletonContext, mkFile string, mods []blueprint.Module) error {
Dan Willemsen218f6562015-07-08 18:13:11 -0700287 buf := &bytes.Buffer{}
288
Dan Willemsen97750522016-02-09 17:43:51 -0800289 fmt.Fprintln(buf, "LOCAL_MODULE_MAKEFILE := $(lastword $(MAKEFILE_LIST))")
Dan Willemsen218f6562015-07-08 18:13:11 -0700290
Dan Willemsen70e17fa2016-07-25 16:00:20 -0700291 type_stats := make(map[string]int)
Dan Willemsen218f6562015-07-08 18:13:11 -0700292 for _, mod := range mods {
293 err := translateAndroidMkModule(ctx, buf, mod)
294 if err != nil {
295 os.Remove(mkFile)
296 return err
297 }
Dan Willemsen70e17fa2016-07-25 16:00:20 -0700298
Colin Cross2465c3d2018-09-28 10:19:18 -0700299 if amod, ok := mod.(Module); ok && ctx.PrimaryModule(amod) == amod {
300 type_stats[ctx.ModuleType(amod)] += 1
Dan Willemsen70e17fa2016-07-25 16:00:20 -0700301 }
302 }
303
304 keys := []string{}
305 fmt.Fprintln(buf, "\nSTATS.SOONG_MODULE_TYPE :=")
306 for k := range type_stats {
307 keys = append(keys, k)
308 }
309 sort.Strings(keys)
310 for _, mod_type := range keys {
311 fmt.Fprintln(buf, "STATS.SOONG_MODULE_TYPE +=", mod_type)
312 fmt.Fprintf(buf, "STATS.SOONG_MODULE_TYPE.%s := %d\n", mod_type, type_stats[mod_type])
Dan Willemsen218f6562015-07-08 18:13:11 -0700313 }
314
315 // Don't write to the file if it hasn't changed
316 if _, err := os.Stat(mkFile); !os.IsNotExist(err) {
317 if data, err := ioutil.ReadFile(mkFile); err == nil {
318 matches := buf.Len() == len(data)
319
320 if matches {
321 for i, value := range buf.Bytes() {
322 if value != data[i] {
323 matches = false
324 break
325 }
326 }
327 }
328
329 if matches {
330 return nil
331 }
332 }
333 }
334
335 return ioutil.WriteFile(mkFile, buf.Bytes(), 0666)
336}
337
Colin Cross0875c522017-11-28 17:34:01 -0800338func translateAndroidMkModule(ctx SingletonContext, w io.Writer, mod blueprint.Module) error {
Colin Cross953d3a22018-09-05 16:23:54 -0700339 defer func() {
340 if r := recover(); r != nil {
341 panic(fmt.Errorf("%s in translateAndroidMkModule for module %s variant %s",
342 r, ctx.ModuleName(mod), ctx.ModuleSubDir(mod)))
343 }
344 }()
345
Colin Cross2465c3d2018-09-28 10:19:18 -0700346 switch x := mod.(type) {
347 case AndroidMkDataProvider:
348 return translateAndroidModule(ctx, w, mod, x)
349 case bootstrap.GoBinaryTool:
350 return translateGoBinaryModule(ctx, w, mod, x)
Jaewoong Jung87a94c02019-04-03 15:47:29 -0700351 case AndroidMkEntriesProvider:
352 return translateAndroidMkEntriesModule(ctx, w, mod, x)
Colin Cross2465c3d2018-09-28 10:19:18 -0700353 default:
Dan Willemsen218f6562015-07-08 18:13:11 -0700354 return nil
355 }
Colin Cross2465c3d2018-09-28 10:19:18 -0700356}
357
358func translateGoBinaryModule(ctx SingletonContext, w io.Writer, mod blueprint.Module,
359 goBinary bootstrap.GoBinaryTool) error {
360
361 name := ctx.ModuleName(mod)
362 fmt.Fprintln(w, ".PHONY:", name)
363 fmt.Fprintln(w, name+":", goBinary.InstallPath())
364 fmt.Fprintln(w, "")
365
366 return nil
367}
368
369func translateAndroidModule(ctx SingletonContext, w io.Writer, mod blueprint.Module,
370 provider AndroidMkDataProvider) error {
Dan Willemsen218f6562015-07-08 18:13:11 -0700371
Colin Cross635c3b02016-05-18 15:37:25 -0700372 amod := mod.(Module).base()
Jaewoong Jung87a94c02019-04-03 15:47:29 -0700373 if shouldSkipAndroidMkProcessing(amod) {
Jeff Gaston088e29e2017-11-29 16:47:17 -0800374 return nil
375 }
376
Colin Cross91825d22017-08-10 16:59:47 -0700377 data := provider.AndroidMk()
Colin Cross53499412017-09-07 13:20:25 -0700378 if data.Include == "" {
379 data.Include = "$(BUILD_PREBUILT)"
380 }
381
Jaewoong Jung87a94c02019-04-03 15:47:29 -0700382 // Get the preamble content through AndroidMkEntries logic.
383 entries := AndroidMkEntries{
384 Class: data.Class,
385 SubName: data.SubName,
386 DistFile: data.DistFile,
387 OutputFile: data.OutputFile,
388 Disabled: data.Disabled,
389 Include: data.Include,
390 Required: data.Required,
Dan Willemsen01a405a2016-06-13 17:19:03 -0700391 }
Jaewoong Jung87a94c02019-04-03 15:47:29 -0700392 entries.fillInEntries(ctx.Config(), ctx.BlueprintFile(mod), mod)
393 // preamble doesn't need the footer content.
394 entries.footer = bytes.Buffer{}
395 entries.write(&data.preamble)
Dan Willemsen01a405a2016-06-13 17:19:03 -0700396
Colin Cross0f86d182017-08-10 17:07:28 -0700397 prefix := ""
398 if amod.ArchSpecific() {
399 switch amod.Os().Class {
400 case Host:
401 prefix = "HOST_"
402 case HostCross:
403 prefix = "HOST_CROSS_"
404 case Device:
405 prefix = "TARGET_"
Colin Crossa2344662016-03-24 13:14:12 -0700406
Dan Willemsen218f6562015-07-08 18:13:11 -0700407 }
408
Dan Willemsen0ef639b2018-10-10 17:02:29 -0700409 if amod.Arch().ArchType != ctx.Config().Targets[amod.Os()][0].Arch.ArchType {
Colin Cross0f86d182017-08-10 17:07:28 -0700410 prefix = "2ND_" + prefix
411 }
Dan Willemsen218f6562015-07-08 18:13:11 -0700412 }
413
Jaewoong Jung87a94c02019-04-03 15:47:29 -0700414 name := provider.BaseModuleName()
Colin Cross0f86d182017-08-10 17:07:28 -0700415 blueprintDir := filepath.Dir(ctx.BlueprintFile(mod))
416
417 if data.Custom != nil {
418 data.Custom(w, name, prefix, blueprintDir, data)
419 } else {
420 WriteAndroidMkData(w, data)
421 }
422
423 return nil
424}
425
426func WriteAndroidMkData(w io.Writer, data AndroidMkData) {
427 if data.Disabled {
428 return
429 }
430
431 if !data.OutputFile.Valid() {
432 return
433 }
434
435 w.Write(data.preamble.Bytes())
436
Colin Crossca860ac2016-01-04 14:34:37 -0800437 for _, extra := range data.Extra {
Colin Cross27a4b052017-08-10 16:32:23 -0700438 extra(w, data.OutputFile.Path())
Dan Willemsen97750522016-02-09 17:43:51 -0800439 }
440
Colin Cross53499412017-09-07 13:20:25 -0700441 fmt.Fprintln(w, "include "+data.Include)
Dan Willemsen218f6562015-07-08 18:13:11 -0700442}
Jaewoong Jung87a94c02019-04-03 15:47:29 -0700443
444func translateAndroidMkEntriesModule(ctx SingletonContext, w io.Writer, mod blueprint.Module,
445 provider AndroidMkEntriesProvider) error {
446 if shouldSkipAndroidMkProcessing(mod.(Module).base()) {
447 return nil
448 }
449
450 entries := provider.AndroidMkEntries()
451 entries.fillInEntries(ctx.Config(), ctx.BlueprintFile(mod), mod)
452
453 entries.write(w)
454
455 return nil
456}
457
458func shouldSkipAndroidMkProcessing(module *ModuleBase) bool {
459 if !module.commonProperties.NamespaceExportedToMake {
460 // TODO(jeffrygaston) do we want to validate that there are no modules being
461 // exported to Kati that depend on this module?
462 return true
463 }
464
465 return !module.Enabled() ||
466 module.commonProperties.SkipInstall ||
467 // Make does not understand LinuxBionic
468 module.Os() == LinuxBionic
469}