blob: 45fd0d065e84f75d4b6475a024561d23ffc6f68c [file] [log] [blame]
Dan Willemsen4b7d5de2016-01-12 23:20:28 -08001// Copyright 2016 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 Willemsen4b7d5de2016-01-12 23:20:28 -080016
17import (
18 "bytes"
Colin Crossd9bbf4b2023-11-17 16:23:48 -080019 "cmp"
Dan Willemsen4b7d5de2016-01-12 23:20:28 -080020 "fmt"
Colin Cross6301c3c2021-09-28 17:40:21 -070021 "path/filepath"
22 "runtime"
Colin Crossd9bbf4b2023-11-17 16:23:48 -080023 "slices"
Dan Willemsen6a6478d2020-07-17 19:28:53 -070024 "sort"
Colin Cross31656952018-05-24 16:11:20 -070025 "strings"
Dan Willemsen4b7d5de2016-01-12 23:20:28 -080026
Colin Cross65494b92019-02-07 14:25:51 -080027 "github.com/google/blueprint"
Colin Crossc3d87d32020-06-04 13:25:17 -070028 "github.com/google/blueprint/pathtools"
Dan Willemsen4b7d5de2016-01-12 23:20:28 -080029 "github.com/google/blueprint/proptools"
30)
31
Dan Albertf5415d72017-08-17 16:19:59 -070032func init() {
33 RegisterMakeVarsProvider(pctx, androidMakeVarsProvider)
34}
35
36func androidMakeVarsProvider(ctx MakeVarsContext) {
Dan Albert1a246272020-07-06 14:49:35 -070037 ctx.Strict("MIN_SUPPORTED_SDK_VERSION", ctx.Config().MinSupportedSdkVersion().String())
Dan Albertf5415d72017-08-17 16:19:59 -070038}
39
Paul Duffin8eb45732022-10-04 19:03:31 +010040// /////////////////////////////////////////////////////////////////////////////
Dan Willemsen6a6478d2020-07-17 19:28:53 -070041
42// BaseMakeVarsContext contains the common functions for other packages to use
43// to declare make variables
44type BaseMakeVarsContext interface {
Dan Willemsen4b7d5de2016-01-12 23:20:28 -080045 Config() Config
Dan Willemsen3fb1fae2018-03-12 15:30:26 -070046 DeviceConfig() DeviceConfig
Colin Cross65494b92019-02-07 14:25:51 -080047 AddNinjaFileDeps(deps ...string)
Colin Cross65494b92019-02-07 14:25:51 -080048
Colin Cross65494b92019-02-07 14:25:51 -080049 Failed() bool
50
Dan Willemsen558e5172016-05-19 16:58:46 -070051 // These are equivalent to Strict and Check, but do not attempt to
52 // evaluate the values before writing them to the Makefile. They can
53 // be used when all ninja variables have already been evaluated through
54 // Eval().
55 StrictRaw(name, value string)
56 CheckRaw(name, value string)
Colin Cross8177ad22019-11-04 10:27:48 -080057
58 // GlobWithDeps returns a list of files that match the specified pattern but do not match any
59 // of the patterns in excludes. It also adds efficient dependencies to rerun the primary
60 // builder whenever a file matching the pattern as added or removed, without rerunning if a
61 // file that does not match the pattern is added to a searched directory.
62 GlobWithDeps(pattern string, excludes []string) ([]string, error)
Colin Crossc3d87d32020-06-04 13:25:17 -070063
64 // Phony creates a phony rule in Make, which will allow additional DistForGoal
65 // dependencies to be added to it. Phony can be called on the same name multiple
66 // times to add additional dependencies.
67 Phony(names string, deps ...Path)
Colin Cross3cda0d82019-09-24 13:40:07 -070068
69 // DistForGoal creates a rule to copy one or more Paths to the artifacts
70 // directory on the build server when the specified goal is built.
71 DistForGoal(goal string, paths ...Path)
72
73 // DistForGoalWithFilename creates a rule to copy a Path to the artifacts
74 // directory on the build server with the given filename when the specified
75 // goal is built.
76 DistForGoalWithFilename(goal string, path Path, filename string)
77
78 // DistForGoals creates a rule to copy one or more Paths to the artifacts
79 // directory on the build server when any of the specified goals are built.
80 DistForGoals(goals []string, paths ...Path)
81
82 // DistForGoalsWithFilename creates a rule to copy a Path to the artifacts
83 // directory on the build server with the given filename when any of the
84 // specified goals are built.
85 DistForGoalsWithFilename(goals []string, path Path, filename string)
Dan Willemsen4b7d5de2016-01-12 23:20:28 -080086}
87
Dan Willemsen6a6478d2020-07-17 19:28:53 -070088// MakeVarsContext contains the set of functions available for MakeVarsProvider
89// and SingletonMakeVarsProvider implementations.
90type MakeVarsContext interface {
91 BaseMakeVarsContext
92
93 ModuleName(module blueprint.Module) string
94 ModuleDir(module blueprint.Module) string
95 ModuleSubDir(module blueprint.Module) string
96 ModuleType(module blueprint.Module) string
Yu Liu663e4502024-08-12 18:23:59 +000097 otherModuleProvider(module blueprint.Module, key blueprint.AnyProviderKey) (any, bool)
Dan Willemsen6a6478d2020-07-17 19:28:53 -070098 BlueprintFile(module blueprint.Module) string
99
100 ModuleErrorf(module blueprint.Module, format string, args ...interface{})
Cole Fausta963b942024-04-11 17:43:00 -0700101 OtherModulePropertyErrorf(module Module, property, format string, args ...interface{})
Dan Willemsen6a6478d2020-07-17 19:28:53 -0700102 Errorf(format string, args ...interface{})
103
104 VisitAllModules(visit func(Module))
105 VisitAllModulesIf(pred func(Module) bool, visit func(Module))
106
107 // Verify the make variable matches the Soong version, fail the build
108 // if it does not. If the make variable is empty, just set it.
109 Strict(name, ninjaStr string)
110 // Check to see if the make variable matches the Soong version, warn if
111 // it does not. If the make variable is empty, just set it.
112 Check(name, ninjaStr string)
113
114 // These are equivalent to the above, but sort the make and soong
115 // variables before comparing them. They also show the unique entries
116 // in each list when displaying the difference, instead of the entire
117 // string.
118 StrictSorted(name, ninjaStr string)
119 CheckSorted(name, ninjaStr string)
120
121 // Evaluates a ninja string and returns the result. Used if more
122 // complicated modification needs to happen before giving it to Make.
123 Eval(ninjaStr string) (string, error)
124}
125
126// MakeVarsModuleContext contains the set of functions available for modules
127// implementing the ModuleMakeVarsProvider interface.
128type MakeVarsModuleContext interface {
129 BaseMakeVarsContext
130}
131
Colin Cross65494b92019-02-07 14:25:51 -0800132var _ PathContext = MakeVarsContext(nil)
133
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800134type MakeVarsProvider func(ctx MakeVarsContext)
135
Colin Cross0875c522017-11-28 17:34:01 -0800136func RegisterMakeVarsProvider(pctx PackageContext, provider MakeVarsProvider) {
Chris Parsonsf3c96ef2020-09-29 02:23:17 -0400137 makeVarsInitProviders = append(makeVarsInitProviders, makeVarsProvider{pctx, provider})
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800138}
139
Colin Crossed023ec2019-02-19 12:38:45 -0800140// SingletonMakeVarsProvider is a Singleton with an extra method to provide extra values to be exported to Make.
141type SingletonMakeVarsProvider interface {
Colin Crossed023ec2019-02-19 12:38:45 -0800142 // MakeVars uses a MakeVarsContext to provide extra values to be exported to Make.
143 MakeVars(ctx MakeVarsContext)
144}
145
Colin Cross06fa5882020-10-29 18:21:38 -0700146var singletonMakeVarsProvidersKey = NewOnceKey("singletonMakeVarsProvidersKey")
147
Colin Cross6ac95762021-11-09 13:17:44 -0800148func getSingletonMakevarsProviders(config Config) *[]makeVarsProvider {
149 return config.Once(singletonMakeVarsProvidersKey, func() interface{} {
150 return &[]makeVarsProvider{}
151 }).(*[]makeVarsProvider)
152}
153
Colin Cross06fa5882020-10-29 18:21:38 -0700154// registerSingletonMakeVarsProvider adds a singleton that implements SingletonMakeVarsProvider to
155// the list of MakeVarsProviders to run.
156func registerSingletonMakeVarsProvider(config Config, singleton SingletonMakeVarsProvider) {
157 // Singletons are registered on the Context and may be different between different Contexts,
158 // for example when running multiple tests. Store the SingletonMakeVarsProviders in the
159 // Config so they are attached to the Context.
Colin Cross6ac95762021-11-09 13:17:44 -0800160 singletonMakeVarsProviders := getSingletonMakevarsProviders(config)
Colin Cross06fa5882020-10-29 18:21:38 -0700161
162 *singletonMakeVarsProviders = append(*singletonMakeVarsProviders,
163 makeVarsProvider{pctx, singletonMakeVarsProviderAdapter(singleton)})
Colin Crossed023ec2019-02-19 12:38:45 -0800164}
165
Colin Cross06fa5882020-10-29 18:21:38 -0700166// singletonMakeVarsProviderAdapter converts a SingletonMakeVarsProvider to a MakeVarsProvider.
167func singletonMakeVarsProviderAdapter(singleton SingletonMakeVarsProvider) MakeVarsProvider {
Colin Crossed023ec2019-02-19 12:38:45 -0800168 return func(ctx MakeVarsContext) { singleton.MakeVars(ctx) }
169}
170
Dan Willemsen6a6478d2020-07-17 19:28:53 -0700171// ModuleMakeVarsProvider is a Module with an extra method to provide extra values to be exported to Make.
172type ModuleMakeVarsProvider interface {
173 Module
174
175 // MakeVars uses a MakeVarsModuleContext to provide extra values to be exported to Make.
176 MakeVars(ctx MakeVarsModuleContext)
177}
178
Paul Duffin8eb45732022-10-04 19:03:31 +0100179// /////////////////////////////////////////////////////////////////////////////
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800180
Colin Cross0875c522017-11-28 17:34:01 -0800181func makeVarsSingletonFunc() Singleton {
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800182 return &makeVarsSingleton{}
183}
184
Colin Cross6ac95762021-11-09 13:17:44 -0800185type makeVarsSingleton struct {
Paul Duffin8eb45732022-10-04 19:03:31 +0100186 varsForTesting []makeVarsVariable
Colin Cross6ac95762021-11-09 13:17:44 -0800187 installsForTesting []byte
Cole Faustd62a4892025-02-07 16:55:11 -0800188 lateForTesting []byte
Colin Cross6ac95762021-11-09 13:17:44 -0800189}
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800190
191type makeVarsProvider struct {
Colin Cross0875c522017-11-28 17:34:01 -0800192 pctx PackageContext
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800193 call MakeVarsProvider
194}
195
Chris Parsonsf3c96ef2020-09-29 02:23:17 -0400196// Collection of makevars providers that are registered in init() methods.
197var makeVarsInitProviders []makeVarsProvider
198
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800199type makeVarsContext struct {
Colin Cross65494b92019-02-07 14:25:51 -0800200 SingletonContext
Colin Crossc3d87d32020-06-04 13:25:17 -0700201 config Config
202 pctx PackageContext
203 vars []makeVarsVariable
204 phonies []phony
Colin Cross3cda0d82019-09-24 13:40:07 -0700205 dists []dist
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800206}
207
208var _ MakeVarsContext = &makeVarsContext{}
209
210type makeVarsVariable struct {
211 name string
212 value string
213 sort bool
214 strict bool
215}
216
Colin Crossc3d87d32020-06-04 13:25:17 -0700217type phony struct {
218 name string
219 deps []string
220}
221
Colin Cross3cda0d82019-09-24 13:40:07 -0700222type dist struct {
223 goals []string
Jihoon Kang593171e2025-02-05 01:54:45 +0000224 paths distCopies
Colin Cross3cda0d82019-09-24 13:40:07 -0700225}
226
Colin Cross0875c522017-11-28 17:34:01 -0800227func (s *makeVarsSingleton) GenerateBuildActions(ctx SingletonContext) {
Jingwen Chencda22c92020-11-23 00:22:30 -0500228 if !ctx.Config().KatiEnabled() {
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800229 return
230 }
231
Colin Cross988414c2020-01-11 01:11:46 +0000232 outFile := absolutePath(PathForOutput(ctx,
233 "make_vars"+proptools.String(ctx.Config().productVariables.Make_suffix)+".mk").String())
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800234
Colin Crossc3d87d32020-06-04 13:25:17 -0700235 lateOutFile := absolutePath(PathForOutput(ctx,
236 "late"+proptools.String(ctx.Config().productVariables.Make_suffix)+".mk").String())
237
Colin Cross6301c3c2021-09-28 17:40:21 -0700238 installsFile := absolutePath(PathForOutput(ctx,
239 "installs"+proptools.String(ctx.Config().productVariables.Make_suffix)+".mk").String())
240
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800241 if ctx.Failed() {
242 return
243 }
244
Colin Cross3cda0d82019-09-24 13:40:07 -0700245 var vars []makeVarsVariable
246 var dists []dist
Colin Crossc3d87d32020-06-04 13:25:17 -0700247 var phonies []phony
Colin Cross6301c3c2021-09-28 17:40:21 -0700248 var katiInstalls []katiInstall
Colin Crossd9bbf4b2023-11-17 16:23:48 -0800249 var katiInitRcInstalls []katiInstall
250 var katiVintfManifestInstalls []katiInstall
Colin Cross6301c3c2021-09-28 17:40:21 -0700251 var katiSymlinks []katiInstall
Colin Cross06fa5882020-10-29 18:21:38 -0700252
253 providers := append([]makeVarsProvider(nil), makeVarsInitProviders...)
Colin Cross6ac95762021-11-09 13:17:44 -0800254 providers = append(providers, *getSingletonMakevarsProviders(ctx.Config())...)
Colin Cross06fa5882020-10-29 18:21:38 -0700255
256 for _, provider := range providers {
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800257 mctx := &makeVarsContext{
Colin Cross65494b92019-02-07 14:25:51 -0800258 SingletonContext: ctx,
259 pctx: provider.pctx,
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800260 }
261
262 provider.call(mctx)
263
264 vars = append(vars, mctx.vars...)
Colin Crossc3d87d32020-06-04 13:25:17 -0700265 phonies = append(phonies, mctx.phonies...)
Colin Cross3cda0d82019-09-24 13:40:07 -0700266 dists = append(dists, mctx.dists...)
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800267 }
268
Cole Faustf2aab5e2025-02-11 13:32:51 -0800269 singletonDists := getSingletonDists(ctx.Config())
270 singletonDists.lock.Lock()
271 dists = append(dists, singletonDists.dists...)
272 singletonDists.lock.Unlock()
273
Dan Willemsen6a6478d2020-07-17 19:28:53 -0700274 ctx.VisitAllModules(func(m Module) {
Cole Fausta963b942024-04-11 17:43:00 -0700275 if provider, ok := m.(ModuleMakeVarsProvider); ok && m.Enabled(ctx) {
Dan Willemsen6a6478d2020-07-17 19:28:53 -0700276 mctx := &makeVarsContext{
277 SingletonContext: ctx,
278 }
279
280 provider.MakeVars(mctx)
281
282 vars = append(vars, mctx.vars...)
283 phonies = append(phonies, mctx.phonies...)
284 dists = append(dists, mctx.dists...)
285 }
Colin Cross6301c3c2021-09-28 17:40:21 -0700286
287 if m.ExportedToMake() {
Yu Liud46e5ae2024-08-15 18:46:17 +0000288 info := OtherModuleProviderOrDefault(ctx, m, InstallFilesProvider)
289 katiInstalls = append(katiInstalls, info.KatiInstalls...)
Yu Liu82a6d142024-08-27 19:02:29 +0000290 katiInitRcInstalls = append(katiInitRcInstalls, info.KatiInitRcInstalls...)
291 katiVintfManifestInstalls = append(katiVintfManifestInstalls, info.KatiVintfInstalls...)
Yu Liud46e5ae2024-08-15 18:46:17 +0000292 katiSymlinks = append(katiSymlinks, info.KatiSymlinks...)
Colin Cross6301c3c2021-09-28 17:40:21 -0700293 }
Cole Faustd62a4892025-02-07 16:55:11 -0800294
295 if distInfo, ok := OtherModuleProvider(ctx, m, DistProvider); ok {
296 dists = append(dists, distInfo.Dists...)
297 }
Dan Willemsen6a6478d2020-07-17 19:28:53 -0700298 })
299
Colin Crossd9bbf4b2023-11-17 16:23:48 -0800300 compareKatiInstalls := func(a, b katiInstall) int {
301 aTo, bTo := a.to.String(), b.to.String()
302 if cmpTo := cmp.Compare(aTo, bTo); cmpTo != 0 {
303 return cmpTo
304 }
305
306 aFrom, bFrom := a.from.String(), b.from.String()
307 return cmp.Compare(aFrom, bFrom)
308 }
309
310 slices.SortFunc(katiInitRcInstalls, compareKatiInstalls)
311 katiInitRcInstalls = slices.CompactFunc(katiInitRcInstalls, func(a, b katiInstall) bool {
312 return compareKatiInstalls(a, b) == 0
313 })
314 katiInstalls = append(katiInstalls, katiInitRcInstalls...)
315
316 slices.SortFunc(katiVintfManifestInstalls, compareKatiInstalls)
317 katiVintfManifestInstalls = slices.CompactFunc(katiVintfManifestInstalls, func(a, b katiInstall) bool {
318 return compareKatiInstalls(a, b) == 0
319 })
320
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800321 if ctx.Failed() {
322 return
323 }
324
Dan Willemsen6a6478d2020-07-17 19:28:53 -0700325 sort.Slice(vars, func(i, j int) bool {
326 return vars[i].name < vars[j].name
327 })
328 sort.Slice(phonies, func(i, j int) bool {
329 return phonies[i].name < phonies[j].name
330 })
331 lessArr := func(a, b []string) bool {
332 if len(a) == len(b) {
333 for i := range a {
334 if a[i] < b[i] {
335 return true
336 }
337 }
338 return false
339 }
340 return len(a) < len(b)
341 }
342 sort.Slice(dists, func(i, j int) bool {
Jihoon Kang593171e2025-02-05 01:54:45 +0000343 return lessArr(dists[i].goals, dists[j].goals) || lessArr(dists[i].paths.Strings(), dists[j].paths.Strings())
Dan Willemsen6a6478d2020-07-17 19:28:53 -0700344 })
345
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800346 outBytes := s.writeVars(vars)
347
Colin Crossc3d87d32020-06-04 13:25:17 -0700348 if err := pathtools.WriteFileIfChanged(outFile, outBytes, 0666); err != nil {
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800349 ctx.Errorf(err.Error())
350 }
Colin Crossc3d87d32020-06-04 13:25:17 -0700351
Colin Cross3cda0d82019-09-24 13:40:07 -0700352 lateOutBytes := s.writeLate(phonies, dists)
Colin Crossc3d87d32020-06-04 13:25:17 -0700353
354 if err := pathtools.WriteFileIfChanged(lateOutFile, lateOutBytes, 0666); err != nil {
355 ctx.Errorf(err.Error())
356 }
357
Colin Crossd9bbf4b2023-11-17 16:23:48 -0800358 installsBytes := s.writeInstalls(katiInstalls, katiSymlinks, katiVintfManifestInstalls)
Colin Cross6301c3c2021-09-28 17:40:21 -0700359 if err := pathtools.WriteFileIfChanged(installsFile, installsBytes, 0666); err != nil {
360 ctx.Errorf(err.Error())
361 }
Colin Cross6ac95762021-11-09 13:17:44 -0800362
Paul Duffin8eb45732022-10-04 19:03:31 +0100363 // Only save state for tests when testing.
364 if ctx.Config().RunningInsideUnitTest() {
365 s.varsForTesting = vars
366 s.installsForTesting = installsBytes
Cole Faustd62a4892025-02-07 16:55:11 -0800367 s.lateForTesting = lateOutBytes
Paul Duffin8eb45732022-10-04 19:03:31 +0100368 }
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800369}
370
371func (s *makeVarsSingleton) writeVars(vars []makeVarsVariable) []byte {
372 buf := &bytes.Buffer{}
373
Dan Willemsen59339a22018-07-22 21:18:45 -0700374 fmt.Fprint(buf, `# Autogenerated file
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800375
376# Compares SOONG_$(1) against $(1), and warns if they are not equal.
377#
378# If the original variable is empty, then just set it to the SOONG_ version.
379#
380# $(1): Name of the variable to check
381# $(2): If not-empty, sort the values before comparing
382# $(3): Extra snippet to run if it does not match
383define soong-compare-var
384ifneq ($$($(1)),)
Dan Willemsen558e5172016-05-19 16:58:46 -0700385 my_val_make := $$(strip $(if $(2),$$(sort $$($(1))),$$($(1))))
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800386 my_val_soong := $(if $(2),$$(sort $$(SOONG_$(1))),$$(SOONG_$(1)))
387 ifneq ($$(my_val_make),$$(my_val_soong))
388 $$(warning $(1) does not match between Make and Soong:)
389 $(if $(2),$$(warning Make adds: $$(filter-out $$(my_val_soong),$$(my_val_make))),$$(warning Make : $$(my_val_make)))
390 $(if $(2),$$(warning Soong adds: $$(filter-out $$(my_val_make),$$(my_val_soong))),$$(warning Soong: $$(my_val_soong)))
391 $(3)
392 endif
393 my_val_make :=
394 my_val_soong :=
395else
396 $(1) := $$(SOONG_$(1))
397endif
Dan Willemsende18f472016-09-30 10:16:38 -0700398.KATI_READONLY := $(1) SOONG_$(1)
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800399endef
400
401my_check_failed := false
402
403`)
404
405 // Write all the strict checks out first so that if one of them errors,
406 // we get all of the strict errors printed, but not the non-strict
407 // warnings.
408 for _, v := range vars {
409 if !v.strict {
410 continue
411 }
412
413 sort := ""
414 if v.sort {
415 sort = "true"
416 }
417
418 fmt.Fprintf(buf, "SOONG_%s := %s\n", v.name, v.value)
419 fmt.Fprintf(buf, "$(eval $(call soong-compare-var,%s,%s,my_check_failed := true))\n\n", v.name, sort)
420 }
421
Dan Willemsen59339a22018-07-22 21:18:45 -0700422 fmt.Fprint(buf, `
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800423ifneq ($(my_check_failed),false)
424 $(error Soong variable check failed)
425endif
426my_check_failed :=
427
428
429`)
430
431 for _, v := range vars {
432 if v.strict {
433 continue
434 }
435
436 sort := ""
437 if v.sort {
438 sort = "true"
439 }
440
441 fmt.Fprintf(buf, "SOONG_%s := %s\n", v.name, v.value)
442 fmt.Fprintf(buf, "$(eval $(call soong-compare-var,%s,%s))\n\n", v.name, sort)
443 }
444
445 fmt.Fprintln(buf, "\nsoong-compare-var :=")
446
Colin Crossc3d87d32020-06-04 13:25:17 -0700447 fmt.Fprintln(buf)
448
449 return buf.Bytes()
450}
451
Colin Cross3cda0d82019-09-24 13:40:07 -0700452func (s *makeVarsSingleton) writeLate(phonies []phony, dists []dist) []byte {
Colin Crossc3d87d32020-06-04 13:25:17 -0700453 buf := &bytes.Buffer{}
454
455 fmt.Fprint(buf, `# Autogenerated file
456
457# Values written by Soong read after parsing all Android.mk files.
458
459
460`)
461
462 for _, phony := range phonies {
463 fmt.Fprintf(buf, ".PHONY: %s\n", phony.name)
464 fmt.Fprintf(buf, "%s: %s\n", phony.name, strings.Join(phony.deps, "\\\n "))
465 }
466
Colin Cross3cda0d82019-09-24 13:40:07 -0700467 fmt.Fprintln(buf)
468
469 for _, dist := range dists {
Colin Crossb5399c82021-11-11 16:33:24 -0800470 fmt.Fprintf(buf, ".PHONY: %s\n", strings.Join(dist.goals, " "))
Colin Cross3cda0d82019-09-24 13:40:07 -0700471 fmt.Fprintf(buf, "$(call dist-for-goals,%s,%s)\n",
Jihoon Kang593171e2025-02-05 01:54:45 +0000472 strings.Join(dist.goals, " "), strings.Join(dist.paths.Strings(), " "))
Colin Cross3cda0d82019-09-24 13:40:07 -0700473 }
474
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800475 return buf.Bytes()
476}
477
Colin Cross6301c3c2021-09-28 17:40:21 -0700478// writeInstalls writes the list of install rules generated by Soong to a makefile. The rules
479// are exported to Make instead of written directly to the ninja file so that main.mk can add
480// the dependencies from the `required` property that are hard to resolve in Soong.
Colin Crossd9bbf4b2023-11-17 16:23:48 -0800481func (s *makeVarsSingleton) writeInstalls(installs, symlinks, katiVintfManifestInstalls []katiInstall) []byte {
Colin Cross6301c3c2021-09-28 17:40:21 -0700482 buf := &bytes.Buffer{}
483
484 fmt.Fprint(buf, `# Autogenerated file
485
486# Values written by Soong to generate install rules that can be amended by Kati.
487
Cole Faust99bec752024-05-09 11:07:20 -0700488EXTRA_INSTALL_ZIPS :=
Colin Cross6301c3c2021-09-28 17:40:21 -0700489`)
490
491 preserveSymlinksFlag := "-d"
492 if runtime.GOOS == "darwin" {
493 preserveSymlinksFlag = "-R"
494 }
495
496 for _, install := range installs {
497 // Write a rule for each install request in the form:
498 // to: from [ deps ] [ | order only deps ]
499 // cp -f -d $< $@ [ && chmod +x $@ ]
500 fmt.Fprintf(buf, "%s: %s", install.to.String(), install.from.String())
501 for _, dep := range install.implicitDeps {
502 fmt.Fprintf(buf, " %s", dep.String())
503 }
Colin Cross50ed1f92021-11-12 17:41:02 -0800504 if extraFiles := install.extraFiles; extraFiles != nil {
505 fmt.Fprintf(buf, " %s", extraFiles.zip.String())
506 }
Colin Cross6301c3c2021-09-28 17:40:21 -0700507 if len(install.orderOnlyDeps) > 0 {
508 fmt.Fprintf(buf, " |")
509 }
510 for _, dep := range install.orderOnlyDeps {
511 fmt.Fprintf(buf, " %s", dep.String())
512 }
513 fmt.Fprintln(buf)
Alessandro Astone2b17a232022-10-25 11:44:59 +0200514 fmt.Fprintln(buf, "\t@echo \"Install: $@\"")
Colin Cross50ed1f92021-11-12 17:41:02 -0800515 fmt.Fprintf(buf, "\trm -f $@ && cp -f %s $< $@\n", preserveSymlinksFlag)
Colin Cross6301c3c2021-09-28 17:40:21 -0700516 if install.executable {
Colin Cross50ed1f92021-11-12 17:41:02 -0800517 fmt.Fprintf(buf, "\tchmod +x $@\n")
Colin Cross6301c3c2021-09-28 17:40:21 -0700518 }
Colin Cross50ed1f92021-11-12 17:41:02 -0800519 if extraFiles := install.extraFiles; extraFiles != nil {
Romain Jobredeaux1cef6292022-05-19 11:11:51 -0400520 fmt.Fprintf(buf, "\t( unzip -qDD -d '%s' '%s' 2>&1 | grep -v \"zipfile is empty\"; exit $${PIPESTATUS[0]} ) || \\\n", extraFiles.dir.String(), extraFiles.zip.String())
521 fmt.Fprintf(buf, "\t ( code=$$?; if [ $$code -ne 0 -a $$code -ne 1 ]; then exit $$code; fi )\n")
Cole Faust07c45372024-05-10 12:39:05 -0700522 fmt.Fprintf(buf, "EXTRA_INSTALL_ZIPS += %s:%s:%s\n", install.to.String(), extraFiles.dir.String(), extraFiles.zip.String())
Colin Cross50ed1f92021-11-12 17:41:02 -0800523 }
Cole Faust99bec752024-05-09 11:07:20 -0700524
Colin Cross6301c3c2021-09-28 17:40:21 -0700525 fmt.Fprintln(buf)
526 }
Cole Faust99bec752024-05-09 11:07:20 -0700527 fmt.Fprintf(buf, ".KATI_READONLY := EXTRA_INSTALL_ZIPS\n")
Cole Faustb23bae72024-05-15 15:44:21 -0700528 fmt.Fprintf(buf, "$(KATI_visibility_prefix EXTRA_INSTALL_ZIPS,build/make/core/Makefile)\n")
Colin Cross6301c3c2021-09-28 17:40:21 -0700529
530 for _, symlink := range symlinks {
531 fmt.Fprintf(buf, "%s:", symlink.to.String())
Colin Cross64002af2021-11-09 16:37:52 -0800532 if symlink.from != nil {
Colin Crossd9bbf4b2023-11-17 16:23:48 -0800533 // The katiVintfManifestInstall doesn't need updating when the target is modified, but we sometimes
534 // have a dependency on a katiVintfManifestInstall to a binary instead of to the binary directly, and
535 // the mtime of the katiVintfManifestInstall must be updated when the binary is modified, so use a
Colin Cross64002af2021-11-09 16:37:52 -0800536 // normal dependency here instead of an order-only dependency.
537 fmt.Fprintf(buf, " %s", symlink.from.String())
538 }
Colin Cross6301c3c2021-09-28 17:40:21 -0700539 for _, dep := range symlink.implicitDeps {
540 fmt.Fprintf(buf, " %s", dep.String())
541 }
Colin Cross64002af2021-11-09 16:37:52 -0800542 if len(symlink.orderOnlyDeps) > 0 {
Colin Cross6301c3c2021-09-28 17:40:21 -0700543 fmt.Fprintf(buf, " |")
544 }
Colin Cross6301c3c2021-09-28 17:40:21 -0700545 for _, dep := range symlink.orderOnlyDeps {
546 fmt.Fprintf(buf, " %s", dep.String())
547 }
548 fmt.Fprintln(buf)
549
550 fromStr := ""
551 if symlink.from != nil {
552 rel, err := filepath.Rel(filepath.Dir(symlink.to.String()), symlink.from.String())
553 if err != nil {
Colin Crossd9bbf4b2023-11-17 16:23:48 -0800554 panic(fmt.Errorf("failed to find relative path for katiVintfManifestInstall from %q to %q: %w",
Colin Cross6301c3c2021-09-28 17:40:21 -0700555 symlink.from.String(), symlink.to.String(), err))
556 }
557 fromStr = rel
558 } else {
559 fromStr = symlink.absFrom
560 }
561
Alessandro Astone2b17a232022-10-25 11:44:59 +0200562 fmt.Fprintln(buf, "\t@echo \"Symlink: $@\"")
Colin Cross6301c3c2021-09-28 17:40:21 -0700563 fmt.Fprintf(buf, "\trm -f $@ && ln -sfn %s $@", fromStr)
564 fmt.Fprintln(buf)
565 fmt.Fprintln(buf)
566 }
567
Colin Crossd9bbf4b2023-11-17 16:23:48 -0800568 for _, install := range katiVintfManifestInstalls {
569 // Write a rule for each vintf install request that calls the copy-vintf-manifest-chedk make function.
570 fmt.Fprintf(buf, "$(eval $(call copy-vintf-manifest-checked, %s, %s))\n", install.from.String(), install.to.String())
571
572 if len(install.implicitDeps) > 0 {
573 panic(fmt.Errorf("unsupported implicitDeps %q in vintf install rule %q", install.implicitDeps, install.to))
574 }
575 if len(install.orderOnlyDeps) > 0 {
576 panic(fmt.Errorf("unsupported orderOnlyDeps %q in vintf install rule %q", install.orderOnlyDeps, install.to))
577 }
578
579 fmt.Fprintln(buf)
580 }
Colin Cross6301c3c2021-09-28 17:40:21 -0700581 return buf.Bytes()
582}
583
Dan Willemsen3fb1fae2018-03-12 15:30:26 -0700584func (c *makeVarsContext) DeviceConfig() DeviceConfig {
Colin Cross65494b92019-02-07 14:25:51 -0800585 return DeviceConfig{c.Config().deviceConfig}
Jiyong Park374510b2018-03-19 18:23:01 +0900586}
587
Colin Cross31656952018-05-24 16:11:20 -0700588var ninjaDescaper = strings.NewReplacer("$$", "$")
589
Dan Willemsen558e5172016-05-19 16:58:46 -0700590func (c *makeVarsContext) Eval(ninjaStr string) (string, error) {
Colin Cross65494b92019-02-07 14:25:51 -0800591 s, err := c.SingletonContext.Eval(c.pctx, ninjaStr)
Colin Cross31656952018-05-24 16:11:20 -0700592 if err != nil {
593 return "", err
594 }
595 // SingletonContext.Eval returns an exapnded string that is valid for a ninja file, de-escape $$ to $ for use
596 // in a Makefile
597 return ninjaDescaper.Replace(s), nil
Dan Willemsen558e5172016-05-19 16:58:46 -0700598}
599
600func (c *makeVarsContext) addVariableRaw(name, value string, strict, sort bool) {
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800601 c.vars = append(c.vars, makeVarsVariable{
602 name: name,
603 value: value,
604 strict: strict,
605 sort: sort,
606 })
607}
608
Dan Willemsen558e5172016-05-19 16:58:46 -0700609func (c *makeVarsContext) addVariable(name, ninjaStr string, strict, sort bool) {
610 value, err := c.Eval(ninjaStr)
611 if err != nil {
Colin Cross65494b92019-02-07 14:25:51 -0800612 c.SingletonContext.Errorf(err.Error())
Dan Willemsen558e5172016-05-19 16:58:46 -0700613 }
614 c.addVariableRaw(name, value, strict, sort)
615}
616
Colin Crossc3d87d32020-06-04 13:25:17 -0700617func (c *makeVarsContext) addPhony(name string, deps []string) {
618 c.phonies = append(c.phonies, phony{name, deps})
619}
620
Jihoon Kang593171e2025-02-05 01:54:45 +0000621func (c *makeVarsContext) addDist(goals []string, paths []distCopy) {
Colin Cross3cda0d82019-09-24 13:40:07 -0700622 c.dists = append(c.dists, dist{
623 goals: goals,
624 paths: paths,
625 })
626}
627
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800628func (c *makeVarsContext) Strict(name, ninjaStr string) {
629 c.addVariable(name, ninjaStr, true, false)
630}
631func (c *makeVarsContext) StrictSorted(name, ninjaStr string) {
632 c.addVariable(name, ninjaStr, true, true)
633}
Dan Willemsen558e5172016-05-19 16:58:46 -0700634func (c *makeVarsContext) StrictRaw(name, value string) {
635 c.addVariableRaw(name, value, true, false)
636}
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800637
638func (c *makeVarsContext) Check(name, ninjaStr string) {
639 c.addVariable(name, ninjaStr, false, false)
640}
641func (c *makeVarsContext) CheckSorted(name, ninjaStr string) {
642 c.addVariable(name, ninjaStr, false, true)
643}
Dan Willemsen558e5172016-05-19 16:58:46 -0700644func (c *makeVarsContext) CheckRaw(name, value string) {
645 c.addVariableRaw(name, value, false, false)
646}
Colin Crossc3d87d32020-06-04 13:25:17 -0700647
648func (c *makeVarsContext) Phony(name string, deps ...Path) {
649 c.addPhony(name, Paths(deps).Strings())
650}
Colin Cross3cda0d82019-09-24 13:40:07 -0700651
652func (c *makeVarsContext) DistForGoal(goal string, paths ...Path) {
653 c.DistForGoals([]string{goal}, paths...)
654}
655
656func (c *makeVarsContext) DistForGoalWithFilename(goal string, path Path, filename string) {
657 c.DistForGoalsWithFilename([]string{goal}, path, filename)
658}
659
660func (c *makeVarsContext) DistForGoals(goals []string, paths ...Path) {
Jihoon Kang593171e2025-02-05 01:54:45 +0000661 var copies distCopies
662 for _, path := range paths {
663 copies = append(copies, distCopy{
664 from: path,
Jihoon Kang409a6432025-02-06 22:14:19 +0000665 dest: path.Base(),
Jihoon Kang593171e2025-02-05 01:54:45 +0000666 })
667 }
668 c.addDist(goals, copies)
Colin Cross3cda0d82019-09-24 13:40:07 -0700669}
670
671func (c *makeVarsContext) DistForGoalsWithFilename(goals []string, path Path, filename string) {
Jihoon Kang593171e2025-02-05 01:54:45 +0000672 c.addDist(goals, distCopies{{from: path, dest: filename}})
Colin Cross3cda0d82019-09-24 13:40:07 -0700673}