blob: 5a9fe7c66b17b48c07f519f8b7dcb9854b9e3822 [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"
19 "fmt"
Colin Cross6301c3c2021-09-28 17:40:21 -070020 "path/filepath"
21 "runtime"
Dan Willemsen6a6478d2020-07-17 19:28:53 -070022 "sort"
Colin Cross31656952018-05-24 16:11:20 -070023 "strings"
Dan Willemsen4b7d5de2016-01-12 23:20:28 -080024
Colin Cross65494b92019-02-07 14:25:51 -080025 "github.com/google/blueprint"
Colin Crossc3d87d32020-06-04 13:25:17 -070026 "github.com/google/blueprint/pathtools"
Dan Willemsen4b7d5de2016-01-12 23:20:28 -080027 "github.com/google/blueprint/proptools"
28)
29
Dan Albertf5415d72017-08-17 16:19:59 -070030func init() {
31 RegisterMakeVarsProvider(pctx, androidMakeVarsProvider)
32}
33
34func androidMakeVarsProvider(ctx MakeVarsContext) {
Dan Albert1a246272020-07-06 14:49:35 -070035 ctx.Strict("MIN_SUPPORTED_SDK_VERSION", ctx.Config().MinSupportedSdkVersion().String())
Dan Albertf5415d72017-08-17 16:19:59 -070036}
37
Paul Duffin8eb45732022-10-04 19:03:31 +010038// /////////////////////////////////////////////////////////////////////////////
Dan Willemsen6a6478d2020-07-17 19:28:53 -070039
40// BaseMakeVarsContext contains the common functions for other packages to use
41// to declare make variables
42type BaseMakeVarsContext interface {
Dan Willemsen4b7d5de2016-01-12 23:20:28 -080043 Config() Config
Dan Willemsen3fb1fae2018-03-12 15:30:26 -070044 DeviceConfig() DeviceConfig
Colin Cross65494b92019-02-07 14:25:51 -080045 AddNinjaFileDeps(deps ...string)
Colin Cross65494b92019-02-07 14:25:51 -080046
Colin Cross65494b92019-02-07 14:25:51 -080047 Failed() bool
48
Dan Willemsen558e5172016-05-19 16:58:46 -070049 // These are equivalent to Strict and Check, but do not attempt to
50 // evaluate the values before writing them to the Makefile. They can
51 // be used when all ninja variables have already been evaluated through
52 // Eval().
53 StrictRaw(name, value string)
54 CheckRaw(name, value string)
Colin Cross8177ad22019-11-04 10:27:48 -080055
56 // GlobWithDeps returns a list of files that match the specified pattern but do not match any
57 // of the patterns in excludes. It also adds efficient dependencies to rerun the primary
58 // builder whenever a file matching the pattern as added or removed, without rerunning if a
59 // file that does not match the pattern is added to a searched directory.
60 GlobWithDeps(pattern string, excludes []string) ([]string, error)
Colin Crossc3d87d32020-06-04 13:25:17 -070061
62 // Phony creates a phony rule in Make, which will allow additional DistForGoal
63 // dependencies to be added to it. Phony can be called on the same name multiple
64 // times to add additional dependencies.
65 Phony(names string, deps ...Path)
Colin Cross3cda0d82019-09-24 13:40:07 -070066
67 // DistForGoal creates a rule to copy one or more Paths to the artifacts
68 // directory on the build server when the specified goal is built.
69 DistForGoal(goal string, paths ...Path)
70
71 // DistForGoalWithFilename creates a rule to copy a Path to the artifacts
72 // directory on the build server with the given filename when the specified
73 // goal is built.
74 DistForGoalWithFilename(goal string, path Path, filename string)
75
76 // DistForGoals creates a rule to copy one or more Paths to the artifacts
77 // directory on the build server when any of the specified goals are built.
78 DistForGoals(goals []string, paths ...Path)
79
80 // DistForGoalsWithFilename creates a rule to copy a Path to the artifacts
81 // directory on the build server with the given filename when any of the
82 // specified goals are built.
83 DistForGoalsWithFilename(goals []string, path Path, filename string)
Dan Willemsen4b7d5de2016-01-12 23:20:28 -080084}
85
Dan Willemsen6a6478d2020-07-17 19:28:53 -070086// MakeVarsContext contains the set of functions available for MakeVarsProvider
87// and SingletonMakeVarsProvider implementations.
88type MakeVarsContext interface {
89 BaseMakeVarsContext
90
91 ModuleName(module blueprint.Module) string
92 ModuleDir(module blueprint.Module) string
93 ModuleSubDir(module blueprint.Module) string
94 ModuleType(module blueprint.Module) string
Colin Cross3c0a83d2023-12-12 14:13:26 -080095 ModuleProvider(module blueprint.Module, key blueprint.AnyProviderKey) any
96 moduleProvider(module blueprint.Module, key blueprint.AnyProviderKey) (any, bool)
Dan Willemsen6a6478d2020-07-17 19:28:53 -070097 BlueprintFile(module blueprint.Module) string
98
99 ModuleErrorf(module blueprint.Module, format string, args ...interface{})
100 Errorf(format string, args ...interface{})
101
102 VisitAllModules(visit func(Module))
103 VisitAllModulesIf(pred func(Module) bool, visit func(Module))
104
105 // Verify the make variable matches the Soong version, fail the build
106 // if it does not. If the make variable is empty, just set it.
107 Strict(name, ninjaStr string)
108 // Check to see if the make variable matches the Soong version, warn if
109 // it does not. If the make variable is empty, just set it.
110 Check(name, ninjaStr string)
111
112 // These are equivalent to the above, but sort the make and soong
113 // variables before comparing them. They also show the unique entries
114 // in each list when displaying the difference, instead of the entire
115 // string.
116 StrictSorted(name, ninjaStr string)
117 CheckSorted(name, ninjaStr string)
118
119 // Evaluates a ninja string and returns the result. Used if more
120 // complicated modification needs to happen before giving it to Make.
121 Eval(ninjaStr string) (string, error)
122}
123
124// MakeVarsModuleContext contains the set of functions available for modules
125// implementing the ModuleMakeVarsProvider interface.
126type MakeVarsModuleContext interface {
127 BaseMakeVarsContext
128}
129
Colin Cross65494b92019-02-07 14:25:51 -0800130var _ PathContext = MakeVarsContext(nil)
131
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800132type MakeVarsProvider func(ctx MakeVarsContext)
133
Colin Cross0875c522017-11-28 17:34:01 -0800134func RegisterMakeVarsProvider(pctx PackageContext, provider MakeVarsProvider) {
Chris Parsonsf3c96ef2020-09-29 02:23:17 -0400135 makeVarsInitProviders = append(makeVarsInitProviders, makeVarsProvider{pctx, provider})
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800136}
137
Colin Crossed023ec2019-02-19 12:38:45 -0800138// SingletonMakeVarsProvider is a Singleton with an extra method to provide extra values to be exported to Make.
139type SingletonMakeVarsProvider interface {
Colin Crossed023ec2019-02-19 12:38:45 -0800140 // MakeVars uses a MakeVarsContext to provide extra values to be exported to Make.
141 MakeVars(ctx MakeVarsContext)
142}
143
Colin Cross06fa5882020-10-29 18:21:38 -0700144var singletonMakeVarsProvidersKey = NewOnceKey("singletonMakeVarsProvidersKey")
145
Colin Cross6ac95762021-11-09 13:17:44 -0800146func getSingletonMakevarsProviders(config Config) *[]makeVarsProvider {
147 return config.Once(singletonMakeVarsProvidersKey, func() interface{} {
148 return &[]makeVarsProvider{}
149 }).(*[]makeVarsProvider)
150}
151
Colin Cross06fa5882020-10-29 18:21:38 -0700152// registerSingletonMakeVarsProvider adds a singleton that implements SingletonMakeVarsProvider to
153// the list of MakeVarsProviders to run.
154func registerSingletonMakeVarsProvider(config Config, singleton SingletonMakeVarsProvider) {
155 // Singletons are registered on the Context and may be different between different Contexts,
156 // for example when running multiple tests. Store the SingletonMakeVarsProviders in the
157 // Config so they are attached to the Context.
Colin Cross6ac95762021-11-09 13:17:44 -0800158 singletonMakeVarsProviders := getSingletonMakevarsProviders(config)
Colin Cross06fa5882020-10-29 18:21:38 -0700159
160 *singletonMakeVarsProviders = append(*singletonMakeVarsProviders,
161 makeVarsProvider{pctx, singletonMakeVarsProviderAdapter(singleton)})
Colin Crossed023ec2019-02-19 12:38:45 -0800162}
163
Colin Cross06fa5882020-10-29 18:21:38 -0700164// singletonMakeVarsProviderAdapter converts a SingletonMakeVarsProvider to a MakeVarsProvider.
165func singletonMakeVarsProviderAdapter(singleton SingletonMakeVarsProvider) MakeVarsProvider {
Colin Crossed023ec2019-02-19 12:38:45 -0800166 return func(ctx MakeVarsContext) { singleton.MakeVars(ctx) }
167}
168
Dan Willemsen6a6478d2020-07-17 19:28:53 -0700169// ModuleMakeVarsProvider is a Module with an extra method to provide extra values to be exported to Make.
170type ModuleMakeVarsProvider interface {
171 Module
172
173 // MakeVars uses a MakeVarsModuleContext to provide extra values to be exported to Make.
174 MakeVars(ctx MakeVarsModuleContext)
175}
176
Paul Duffin8eb45732022-10-04 19:03:31 +0100177// /////////////////////////////////////////////////////////////////////////////
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800178
Colin Cross0875c522017-11-28 17:34:01 -0800179func makeVarsSingletonFunc() Singleton {
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800180 return &makeVarsSingleton{}
181}
182
Colin Cross6ac95762021-11-09 13:17:44 -0800183type makeVarsSingleton struct {
Paul Duffin8eb45732022-10-04 19:03:31 +0100184 varsForTesting []makeVarsVariable
Colin Cross6ac95762021-11-09 13:17:44 -0800185 installsForTesting []byte
186}
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800187
188type makeVarsProvider struct {
Colin Cross0875c522017-11-28 17:34:01 -0800189 pctx PackageContext
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800190 call MakeVarsProvider
191}
192
Chris Parsonsf3c96ef2020-09-29 02:23:17 -0400193// Collection of makevars providers that are registered in init() methods.
194var makeVarsInitProviders []makeVarsProvider
195
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800196type makeVarsContext struct {
Colin Cross65494b92019-02-07 14:25:51 -0800197 SingletonContext
Colin Crossc3d87d32020-06-04 13:25:17 -0700198 config Config
199 pctx PackageContext
200 vars []makeVarsVariable
201 phonies []phony
Colin Cross3cda0d82019-09-24 13:40:07 -0700202 dists []dist
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800203}
204
205var _ MakeVarsContext = &makeVarsContext{}
206
207type makeVarsVariable struct {
208 name string
209 value string
210 sort bool
211 strict bool
212}
213
Colin Crossc3d87d32020-06-04 13:25:17 -0700214type phony struct {
215 name string
216 deps []string
217}
218
Colin Cross3cda0d82019-09-24 13:40:07 -0700219type dist struct {
220 goals []string
221 paths []string
222}
223
Colin Cross0875c522017-11-28 17:34:01 -0800224func (s *makeVarsSingleton) GenerateBuildActions(ctx SingletonContext) {
Jingwen Chencda22c92020-11-23 00:22:30 -0500225 if !ctx.Config().KatiEnabled() {
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800226 return
227 }
228
Colin Cross988414c2020-01-11 01:11:46 +0000229 outFile := absolutePath(PathForOutput(ctx,
230 "make_vars"+proptools.String(ctx.Config().productVariables.Make_suffix)+".mk").String())
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800231
Colin Crossc3d87d32020-06-04 13:25:17 -0700232 lateOutFile := absolutePath(PathForOutput(ctx,
233 "late"+proptools.String(ctx.Config().productVariables.Make_suffix)+".mk").String())
234
Colin Cross6301c3c2021-09-28 17:40:21 -0700235 installsFile := absolutePath(PathForOutput(ctx,
236 "installs"+proptools.String(ctx.Config().productVariables.Make_suffix)+".mk").String())
237
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800238 if ctx.Failed() {
239 return
240 }
241
Colin Cross3cda0d82019-09-24 13:40:07 -0700242 var vars []makeVarsVariable
243 var dists []dist
Colin Crossc3d87d32020-06-04 13:25:17 -0700244 var phonies []phony
Colin Cross6301c3c2021-09-28 17:40:21 -0700245 var katiInstalls []katiInstall
246 var katiSymlinks []katiInstall
Colin Cross06fa5882020-10-29 18:21:38 -0700247
248 providers := append([]makeVarsProvider(nil), makeVarsInitProviders...)
Colin Cross6ac95762021-11-09 13:17:44 -0800249 providers = append(providers, *getSingletonMakevarsProviders(ctx.Config())...)
Colin Cross06fa5882020-10-29 18:21:38 -0700250
251 for _, provider := range providers {
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800252 mctx := &makeVarsContext{
Colin Cross65494b92019-02-07 14:25:51 -0800253 SingletonContext: ctx,
254 pctx: provider.pctx,
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800255 }
256
257 provider.call(mctx)
258
259 vars = append(vars, mctx.vars...)
Colin Crossc3d87d32020-06-04 13:25:17 -0700260 phonies = append(phonies, mctx.phonies...)
Colin Cross3cda0d82019-09-24 13:40:07 -0700261 dists = append(dists, mctx.dists...)
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800262 }
263
Dan Willemsen6a6478d2020-07-17 19:28:53 -0700264 ctx.VisitAllModules(func(m Module) {
Jiyong Parkf78531b2020-09-09 17:14:28 +0900265 if provider, ok := m.(ModuleMakeVarsProvider); ok && m.Enabled() {
Dan Willemsen6a6478d2020-07-17 19:28:53 -0700266 mctx := &makeVarsContext{
267 SingletonContext: ctx,
268 }
269
270 provider.MakeVars(mctx)
271
272 vars = append(vars, mctx.vars...)
273 phonies = append(phonies, mctx.phonies...)
274 dists = append(dists, mctx.dists...)
275 }
Colin Cross6301c3c2021-09-28 17:40:21 -0700276
277 if m.ExportedToMake() {
278 katiInstalls = append(katiInstalls, m.base().katiInstalls...)
279 katiSymlinks = append(katiSymlinks, m.base().katiSymlinks...)
280 }
Dan Willemsen6a6478d2020-07-17 19:28:53 -0700281 })
282
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800283 if ctx.Failed() {
284 return
285 }
286
Dan Willemsen6a6478d2020-07-17 19:28:53 -0700287 sort.Slice(vars, func(i, j int) bool {
288 return vars[i].name < vars[j].name
289 })
290 sort.Slice(phonies, func(i, j int) bool {
291 return phonies[i].name < phonies[j].name
292 })
293 lessArr := func(a, b []string) bool {
294 if len(a) == len(b) {
295 for i := range a {
296 if a[i] < b[i] {
297 return true
298 }
299 }
300 return false
301 }
302 return len(a) < len(b)
303 }
304 sort.Slice(dists, func(i, j int) bool {
305 return lessArr(dists[i].goals, dists[j].goals) || lessArr(dists[i].paths, dists[j].paths)
306 })
307
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800308 outBytes := s.writeVars(vars)
309
Colin Crossc3d87d32020-06-04 13:25:17 -0700310 if err := pathtools.WriteFileIfChanged(outFile, outBytes, 0666); err != nil {
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800311 ctx.Errorf(err.Error())
312 }
Colin Crossc3d87d32020-06-04 13:25:17 -0700313
Colin Cross3cda0d82019-09-24 13:40:07 -0700314 lateOutBytes := s.writeLate(phonies, dists)
Colin Crossc3d87d32020-06-04 13:25:17 -0700315
316 if err := pathtools.WriteFileIfChanged(lateOutFile, lateOutBytes, 0666); err != nil {
317 ctx.Errorf(err.Error())
318 }
319
Colin Cross6301c3c2021-09-28 17:40:21 -0700320 installsBytes := s.writeInstalls(katiInstalls, katiSymlinks)
321 if err := pathtools.WriteFileIfChanged(installsFile, installsBytes, 0666); err != nil {
322 ctx.Errorf(err.Error())
323 }
Colin Cross6ac95762021-11-09 13:17:44 -0800324
Paul Duffin8eb45732022-10-04 19:03:31 +0100325 // Only save state for tests when testing.
326 if ctx.Config().RunningInsideUnitTest() {
327 s.varsForTesting = vars
328 s.installsForTesting = installsBytes
329 }
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800330}
331
332func (s *makeVarsSingleton) writeVars(vars []makeVarsVariable) []byte {
333 buf := &bytes.Buffer{}
334
Dan Willemsen59339a22018-07-22 21:18:45 -0700335 fmt.Fprint(buf, `# Autogenerated file
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800336
337# Compares SOONG_$(1) against $(1), and warns if they are not equal.
338#
339# If the original variable is empty, then just set it to the SOONG_ version.
340#
341# $(1): Name of the variable to check
342# $(2): If not-empty, sort the values before comparing
343# $(3): Extra snippet to run if it does not match
344define soong-compare-var
345ifneq ($$($(1)),)
Dan Willemsen558e5172016-05-19 16:58:46 -0700346 my_val_make := $$(strip $(if $(2),$$(sort $$($(1))),$$($(1))))
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800347 my_val_soong := $(if $(2),$$(sort $$(SOONG_$(1))),$$(SOONG_$(1)))
348 ifneq ($$(my_val_make),$$(my_val_soong))
349 $$(warning $(1) does not match between Make and Soong:)
350 $(if $(2),$$(warning Make adds: $$(filter-out $$(my_val_soong),$$(my_val_make))),$$(warning Make : $$(my_val_make)))
351 $(if $(2),$$(warning Soong adds: $$(filter-out $$(my_val_make),$$(my_val_soong))),$$(warning Soong: $$(my_val_soong)))
352 $(3)
353 endif
354 my_val_make :=
355 my_val_soong :=
356else
357 $(1) := $$(SOONG_$(1))
358endif
Dan Willemsende18f472016-09-30 10:16:38 -0700359.KATI_READONLY := $(1) SOONG_$(1)
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800360endef
361
362my_check_failed := false
363
364`)
365
366 // Write all the strict checks out first so that if one of them errors,
367 // we get all of the strict errors printed, but not the non-strict
368 // warnings.
369 for _, v := range vars {
370 if !v.strict {
371 continue
372 }
373
374 sort := ""
375 if v.sort {
376 sort = "true"
377 }
378
379 fmt.Fprintf(buf, "SOONG_%s := %s\n", v.name, v.value)
380 fmt.Fprintf(buf, "$(eval $(call soong-compare-var,%s,%s,my_check_failed := true))\n\n", v.name, sort)
381 }
382
Dan Willemsen59339a22018-07-22 21:18:45 -0700383 fmt.Fprint(buf, `
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800384ifneq ($(my_check_failed),false)
385 $(error Soong variable check failed)
386endif
387my_check_failed :=
388
389
390`)
391
392 for _, v := range vars {
393 if v.strict {
394 continue
395 }
396
397 sort := ""
398 if v.sort {
399 sort = "true"
400 }
401
402 fmt.Fprintf(buf, "SOONG_%s := %s\n", v.name, v.value)
403 fmt.Fprintf(buf, "$(eval $(call soong-compare-var,%s,%s))\n\n", v.name, sort)
404 }
405
406 fmt.Fprintln(buf, "\nsoong-compare-var :=")
407
Colin Crossc3d87d32020-06-04 13:25:17 -0700408 fmt.Fprintln(buf)
409
410 return buf.Bytes()
411}
412
Colin Cross3cda0d82019-09-24 13:40:07 -0700413func (s *makeVarsSingleton) writeLate(phonies []phony, dists []dist) []byte {
Colin Crossc3d87d32020-06-04 13:25:17 -0700414 buf := &bytes.Buffer{}
415
416 fmt.Fprint(buf, `# Autogenerated file
417
418# Values written by Soong read after parsing all Android.mk files.
419
420
421`)
422
423 for _, phony := range phonies {
424 fmt.Fprintf(buf, ".PHONY: %s\n", phony.name)
425 fmt.Fprintf(buf, "%s: %s\n", phony.name, strings.Join(phony.deps, "\\\n "))
426 }
427
Colin Cross3cda0d82019-09-24 13:40:07 -0700428 fmt.Fprintln(buf)
429
430 for _, dist := range dists {
Colin Crossb5399c82021-11-11 16:33:24 -0800431 fmt.Fprintf(buf, ".PHONY: %s\n", strings.Join(dist.goals, " "))
Colin Cross3cda0d82019-09-24 13:40:07 -0700432 fmt.Fprintf(buf, "$(call dist-for-goals,%s,%s)\n",
433 strings.Join(dist.goals, " "), strings.Join(dist.paths, " "))
434 }
435
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800436 return buf.Bytes()
437}
438
Colin Cross6301c3c2021-09-28 17:40:21 -0700439// writeInstalls writes the list of install rules generated by Soong to a makefile. The rules
440// are exported to Make instead of written directly to the ninja file so that main.mk can add
441// the dependencies from the `required` property that are hard to resolve in Soong.
442func (s *makeVarsSingleton) writeInstalls(installs, symlinks []katiInstall) []byte {
443 buf := &bytes.Buffer{}
444
445 fmt.Fprint(buf, `# Autogenerated file
446
447# Values written by Soong to generate install rules that can be amended by Kati.
448
449
450`)
451
452 preserveSymlinksFlag := "-d"
453 if runtime.GOOS == "darwin" {
454 preserveSymlinksFlag = "-R"
455 }
456
457 for _, install := range installs {
458 // Write a rule for each install request in the form:
459 // to: from [ deps ] [ | order only deps ]
460 // cp -f -d $< $@ [ && chmod +x $@ ]
461 fmt.Fprintf(buf, "%s: %s", install.to.String(), install.from.String())
462 for _, dep := range install.implicitDeps {
463 fmt.Fprintf(buf, " %s", dep.String())
464 }
Colin Cross50ed1f92021-11-12 17:41:02 -0800465 if extraFiles := install.extraFiles; extraFiles != nil {
466 fmt.Fprintf(buf, " %s", extraFiles.zip.String())
467 }
Colin Cross6301c3c2021-09-28 17:40:21 -0700468 if len(install.orderOnlyDeps) > 0 {
469 fmt.Fprintf(buf, " |")
470 }
471 for _, dep := range install.orderOnlyDeps {
472 fmt.Fprintf(buf, " %s", dep.String())
473 }
474 fmt.Fprintln(buf)
Alessandro Astone2b17a232022-10-25 11:44:59 +0200475 fmt.Fprintln(buf, "\t@echo \"Install: $@\"")
Colin Cross50ed1f92021-11-12 17:41:02 -0800476 fmt.Fprintf(buf, "\trm -f $@ && cp -f %s $< $@\n", preserveSymlinksFlag)
Colin Cross6301c3c2021-09-28 17:40:21 -0700477 if install.executable {
Colin Cross50ed1f92021-11-12 17:41:02 -0800478 fmt.Fprintf(buf, "\tchmod +x $@\n")
Colin Cross6301c3c2021-09-28 17:40:21 -0700479 }
Colin Cross50ed1f92021-11-12 17:41:02 -0800480 if extraFiles := install.extraFiles; extraFiles != nil {
Romain Jobredeaux1cef6292022-05-19 11:11:51 -0400481 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())
482 fmt.Fprintf(buf, "\t ( code=$$?; if [ $$code -ne 0 -a $$code -ne 1 ]; then exit $$code; fi )\n")
Colin Cross50ed1f92021-11-12 17:41:02 -0800483 }
Colin Cross6301c3c2021-09-28 17:40:21 -0700484 fmt.Fprintln(buf)
485 }
486
487 for _, symlink := range symlinks {
488 fmt.Fprintf(buf, "%s:", symlink.to.String())
Colin Cross64002af2021-11-09 16:37:52 -0800489 if symlink.from != nil {
490 // The symlink doesn't need updating when the target is modified, but we sometimes
491 // have a dependency on a symlink to a binary instead of to the binary directly, and
492 // the mtime of the symlink must be updated when the binary is modified, so use a
493 // normal dependency here instead of an order-only dependency.
494 fmt.Fprintf(buf, " %s", symlink.from.String())
495 }
Colin Cross6301c3c2021-09-28 17:40:21 -0700496 for _, dep := range symlink.implicitDeps {
497 fmt.Fprintf(buf, " %s", dep.String())
498 }
Colin Cross64002af2021-11-09 16:37:52 -0800499 if len(symlink.orderOnlyDeps) > 0 {
Colin Cross6301c3c2021-09-28 17:40:21 -0700500 fmt.Fprintf(buf, " |")
501 }
Colin Cross6301c3c2021-09-28 17:40:21 -0700502 for _, dep := range symlink.orderOnlyDeps {
503 fmt.Fprintf(buf, " %s", dep.String())
504 }
505 fmt.Fprintln(buf)
506
507 fromStr := ""
508 if symlink.from != nil {
509 rel, err := filepath.Rel(filepath.Dir(symlink.to.String()), symlink.from.String())
510 if err != nil {
511 panic(fmt.Errorf("failed to find relative path for symlink from %q to %q: %w",
512 symlink.from.String(), symlink.to.String(), err))
513 }
514 fromStr = rel
515 } else {
516 fromStr = symlink.absFrom
517 }
518
Alessandro Astone2b17a232022-10-25 11:44:59 +0200519 fmt.Fprintln(buf, "\t@echo \"Symlink: $@\"")
Colin Cross6301c3c2021-09-28 17:40:21 -0700520 fmt.Fprintf(buf, "\trm -f $@ && ln -sfn %s $@", fromStr)
521 fmt.Fprintln(buf)
522 fmt.Fprintln(buf)
523 }
524
525 return buf.Bytes()
526}
527
Dan Willemsen3fb1fae2018-03-12 15:30:26 -0700528func (c *makeVarsContext) DeviceConfig() DeviceConfig {
Colin Cross65494b92019-02-07 14:25:51 -0800529 return DeviceConfig{c.Config().deviceConfig}
Jiyong Park374510b2018-03-19 18:23:01 +0900530}
531
Colin Cross31656952018-05-24 16:11:20 -0700532var ninjaDescaper = strings.NewReplacer("$$", "$")
533
Dan Willemsen558e5172016-05-19 16:58:46 -0700534func (c *makeVarsContext) Eval(ninjaStr string) (string, error) {
Colin Cross65494b92019-02-07 14:25:51 -0800535 s, err := c.SingletonContext.Eval(c.pctx, ninjaStr)
Colin Cross31656952018-05-24 16:11:20 -0700536 if err != nil {
537 return "", err
538 }
539 // SingletonContext.Eval returns an exapnded string that is valid for a ninja file, de-escape $$ to $ for use
540 // in a Makefile
541 return ninjaDescaper.Replace(s), nil
Dan Willemsen558e5172016-05-19 16:58:46 -0700542}
543
544func (c *makeVarsContext) addVariableRaw(name, value string, strict, sort bool) {
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800545 c.vars = append(c.vars, makeVarsVariable{
546 name: name,
547 value: value,
548 strict: strict,
549 sort: sort,
550 })
551}
552
Dan Willemsen558e5172016-05-19 16:58:46 -0700553func (c *makeVarsContext) addVariable(name, ninjaStr string, strict, sort bool) {
554 value, err := c.Eval(ninjaStr)
555 if err != nil {
Colin Cross65494b92019-02-07 14:25:51 -0800556 c.SingletonContext.Errorf(err.Error())
Dan Willemsen558e5172016-05-19 16:58:46 -0700557 }
558 c.addVariableRaw(name, value, strict, sort)
559}
560
Colin Crossc3d87d32020-06-04 13:25:17 -0700561func (c *makeVarsContext) addPhony(name string, deps []string) {
562 c.phonies = append(c.phonies, phony{name, deps})
563}
564
Colin Cross3cda0d82019-09-24 13:40:07 -0700565func (c *makeVarsContext) addDist(goals []string, paths []string) {
566 c.dists = append(c.dists, dist{
567 goals: goals,
568 paths: paths,
569 })
570}
571
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800572func (c *makeVarsContext) Strict(name, ninjaStr string) {
573 c.addVariable(name, ninjaStr, true, false)
574}
575func (c *makeVarsContext) StrictSorted(name, ninjaStr string) {
576 c.addVariable(name, ninjaStr, true, true)
577}
Dan Willemsen558e5172016-05-19 16:58:46 -0700578func (c *makeVarsContext) StrictRaw(name, value string) {
579 c.addVariableRaw(name, value, true, false)
580}
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800581
582func (c *makeVarsContext) Check(name, ninjaStr string) {
583 c.addVariable(name, ninjaStr, false, false)
584}
585func (c *makeVarsContext) CheckSorted(name, ninjaStr string) {
586 c.addVariable(name, ninjaStr, false, true)
587}
Dan Willemsen558e5172016-05-19 16:58:46 -0700588func (c *makeVarsContext) CheckRaw(name, value string) {
589 c.addVariableRaw(name, value, false, false)
590}
Colin Crossc3d87d32020-06-04 13:25:17 -0700591
592func (c *makeVarsContext) Phony(name string, deps ...Path) {
593 c.addPhony(name, Paths(deps).Strings())
594}
Colin Cross3cda0d82019-09-24 13:40:07 -0700595
596func (c *makeVarsContext) DistForGoal(goal string, paths ...Path) {
597 c.DistForGoals([]string{goal}, paths...)
598}
599
600func (c *makeVarsContext) DistForGoalWithFilename(goal string, path Path, filename string) {
601 c.DistForGoalsWithFilename([]string{goal}, path, filename)
602}
603
604func (c *makeVarsContext) DistForGoals(goals []string, paths ...Path) {
605 c.addDist(goals, Paths(paths).Strings())
606}
607
608func (c *makeVarsContext) DistForGoalsWithFilename(goals []string, path Path, filename string) {
609 c.addDist(goals, []string{path.String() + ":" + filename})
610}