• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright 2015 Google Inc. All rights reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package android
16
17// This is the primary location to write and read all configuration values and
18// product variables necessary for soong_build's operation.
19
20import (
21	"bytes"
22	"encoding/json"
23	"fmt"
24	"os"
25	"path/filepath"
26	"reflect"
27	"runtime"
28	"strconv"
29	"strings"
30	"sync"
31
32	"github.com/google/blueprint"
33	"github.com/google/blueprint/bootstrap"
34	"github.com/google/blueprint/pathtools"
35	"github.com/google/blueprint/proptools"
36
37	"android/soong/android/soongconfig"
38	"android/soong/bazel"
39	"android/soong/remoteexec"
40	"android/soong/starlark_fmt"
41)
42
43// Bool re-exports proptools.Bool for the android package.
44var Bool = proptools.Bool
45
46// String re-exports proptools.String for the android package.
47var String = proptools.String
48
49// StringDefault re-exports proptools.StringDefault for the android package.
50var StringDefault = proptools.StringDefault
51
52// FutureApiLevelInt is a placeholder constant for unreleased API levels.
53const FutureApiLevelInt = 10000
54
55// PrivateApiLevel represents the api level of SdkSpecPrivate (sdk_version: "")
56// This api_level exists to differentiate user-provided "" from "current" sdk_version
57// The differentiation is necessary to enable different validation rules for these two possible values.
58var PrivateApiLevel = ApiLevel{
59	value:     "current",             // The value is current since aidl expects `current` as the default (TestAidlFlagsWithMinSdkVersion)
60	number:    FutureApiLevelInt + 1, // This is used to differentiate it from FutureApiLevel
61	isPreview: true,
62}
63
64// FutureApiLevel represents unreleased API levels.
65var FutureApiLevel = ApiLevel{
66	value:     "current",
67	number:    FutureApiLevelInt,
68	isPreview: true,
69}
70
71// The product variables file name, containing product config from Kati.
72const productVariablesFileName = "soong.variables"
73
74// A Config object represents the entire build configuration for Android.
75type Config struct {
76	*config
77}
78
79type SoongBuildMode int
80
81type CmdArgs struct {
82	bootstrap.Args
83	RunGoTests  bool
84	OutDir      string
85	SoongOutDir string
86
87	SymlinkForestMarker string
88	Bp2buildMarker      string
89	BazelQueryViewDir   string
90	BazelApiBp2buildDir string
91	ModuleGraphFile     string
92	ModuleActionsFile   string
93	DocFile             string
94
95	MultitreeBuild bool
96
97	BazelMode                bool
98	BazelModeDev             bool
99	BazelModeStaging         bool
100	BazelForceEnabledModules string
101
102	UseBazelProxy bool
103
104	BuildFromTextStub bool
105}
106
107// Build modes that soong_build can run as.
108const (
109	// Don't use bazel at all during module analysis.
110	AnalysisNoBazel SoongBuildMode = iota
111
112	// Symlink fores mode: merge two directory trees into a symlink forest
113	SymlinkForest
114
115	// Bp2build mode: Generate BUILD files from blueprint files and exit.
116	Bp2build
117
118	// Generate BUILD files which faithfully represent the dependency graph of
119	// blueprint modules. Individual BUILD targets will not, however, faitfhully
120	// express build semantics.
121	GenerateQueryView
122
123	// Generate BUILD files for API contributions to API surfaces
124	ApiBp2build
125
126	// Create a JSON representation of the module graph and exit.
127	GenerateModuleGraph
128
129	// Generate a documentation file for module type definitions and exit.
130	GenerateDocFile
131
132	// Use bazel during analysis of many allowlisted build modules. The allowlist
133	// is considered a "developer mode" allowlist, as some modules may be
134	// allowlisted on an experimental basis.
135	BazelDevMode
136
137	// Use bazel during analysis of a few allowlisted build modules. The allowlist
138	// is considered "staging, as these are modules being prepared to be released
139	// into prod mode shortly after.
140	BazelStagingMode
141
142	// Use bazel during analysis of build modules from an allowlist carefully
143	// curated by the build team to be proven stable.
144	BazelProdMode
145)
146
147// SoongOutDir returns the build output directory for the configuration.
148func (c Config) SoongOutDir() string {
149	return c.soongOutDir
150}
151
152func (c Config) OutDir() string {
153	return c.outDir
154}
155
156func (c Config) RunGoTests() bool {
157	return c.runGoTests
158}
159
160func (c Config) DebugCompilation() bool {
161	return false // Never compile Go code in the main build for debugging
162}
163
164func (c Config) Subninjas() []string {
165	return []string{}
166}
167
168func (c Config) PrimaryBuilderInvocations() []bootstrap.PrimaryBuilderInvocation {
169	return []bootstrap.PrimaryBuilderInvocation{}
170}
171
172// RunningInsideUnitTest returns true if this code is being run as part of a Soong unit test.
173func (c Config) RunningInsideUnitTest() bool {
174	return c.config.TestProductVariables != nil
175}
176
177// MaxPageSizeSupported returns the max page size supported by the device. This
178// value will define the ELF segment alignment for binaries (executables and
179// shared libraries).
180func (c Config) MaxPageSizeSupported() string {
181	return String(c.config.productVariables.DeviceMaxPageSizeSupported)
182}
183
184// A DeviceConfig object represents the configuration for a particular device
185// being built. For now there will only be one of these, but in the future there
186// may be multiple devices being built.
187type DeviceConfig struct {
188	*deviceConfig
189}
190
191// VendorConfig represents the configuration for vendor-specific behavior.
192type VendorConfig soongconfig.SoongConfig
193
194// Definition of general build configuration for soong_build. Some of these
195// product configuration values are read from Kati-generated soong.variables.
196type config struct {
197	// Options configurable with soong.variables
198	productVariables productVariables
199
200	// Only available on configs created by TestConfig
201	TestProductVariables *productVariables
202
203	// A specialized context object for Bazel/Soong mixed builds and migration
204	// purposes.
205	BazelContext BazelContext
206
207	ProductVariablesFileName string
208
209	// BuildOS stores the OsType for the OS that the build is running on.
210	BuildOS OsType
211
212	// BuildArch stores the ArchType for the CPU that the build is running on.
213	BuildArch ArchType
214
215	Targets                  map[OsType][]Target
216	BuildOSTarget            Target // the Target for tools run on the build machine
217	BuildOSCommonTarget      Target // the Target for common (java) tools run on the build machine
218	AndroidCommonTarget      Target // the Target for common modules for the Android device
219	AndroidFirstDeviceTarget Target // the first Target for modules for the Android device
220
221	// multilibConflicts for an ArchType is true if there is earlier configured
222	// device architecture with the same multilib value.
223	multilibConflicts map[ArchType]bool
224
225	deviceConfig *deviceConfig
226
227	outDir         string // The output directory (usually out/)
228	soongOutDir    string
229	moduleListFile string // the path to the file which lists blueprint files to parse.
230
231	runGoTests bool
232
233	env       map[string]string
234	envLock   sync.Mutex
235	envDeps   map[string]string
236	envFrozen bool
237
238	// Changes behavior based on whether Kati runs after soong_build, or if soong_build
239	// runs standalone.
240	katiEnabled bool
241
242	captureBuild      bool // true for tests, saves build parameters for each module
243	ignoreEnvironment bool // true for tests, returns empty from all Getenv calls
244
245	fs         pathtools.FileSystem
246	mockBpList string
247
248	BuildMode                      SoongBuildMode
249	Bp2buildPackageConfig          Bp2BuildConversionAllowlist
250	Bp2buildSoongConfigDefinitions soongconfig.Bp2BuildSoongConfigDefinitions
251
252	// If MultitreeBuild is true then this is one inner tree of a multitree
253	// build directed by the multitree orchestrator.
254	MultitreeBuild bool
255
256	// If testAllowNonExistentPaths is true then PathForSource and PathForModuleSrc won't error
257	// in tests when a path doesn't exist.
258	TestAllowNonExistentPaths bool
259
260	// The list of files that when changed, must invalidate soong_build to
261	// regenerate build.ninja.
262	ninjaFileDepsSet sync.Map
263
264	OncePer
265
266	// These fields are only used for metrics collection. A module should be added
267	// to these maps only if its implementation supports Bazel handling in mixed
268	// builds. A module being in the "enabled" list indicates that there is a
269	// variant of that module for which bazel-handling actually took place.
270	// A module being in the "disabled" list indicates that there is a variant of
271	// that module for which bazel-handling was denied.
272	mixedBuildsLock           sync.Mutex
273	mixedBuildEnabledModules  map[string]struct{}
274	mixedBuildDisabledModules map[string]struct{}
275
276	// These are modules to be built with Bazel beyond the allowlisted/build-mode
277	// specified modules. They are passed via the command-line flag
278	// "--bazel-force-enabled-modules"
279	bazelForceEnabledModules map[string]struct{}
280
281	// If true, for any requests to Bazel, communicate with a Bazel proxy using
282	// unix sockets, instead of spawning Bazel as a subprocess.
283	UseBazelProxy bool
284
285	// If buildFromTextStub is true then the Java API stubs are
286	// built from the signature text files, not the source Java files.
287	buildFromTextStub bool
288}
289
290type deviceConfig struct {
291	config *config
292	OncePer
293}
294
295type jsonConfigurable interface {
296	SetDefaultConfig()
297}
298
299func loadConfig(config *config) error {
300	return loadFromConfigFile(&config.productVariables, absolutePath(config.ProductVariablesFileName))
301}
302
303// loadFromConfigFile loads and decodes configuration options from a JSON file
304// in the current working directory.
305func loadFromConfigFile(configurable *productVariables, filename string) error {
306	// Try to open the file
307	configFileReader, err := os.Open(filename)
308	defer configFileReader.Close()
309	if os.IsNotExist(err) {
310		// Need to create a file, so that blueprint & ninja don't get in
311		// a dependency tracking loop.
312		// Make a file-configurable-options with defaults, write it out using
313		// a json writer.
314		configurable.SetDefaultConfig()
315		err = saveToConfigFile(configurable, filename)
316		if err != nil {
317			return err
318		}
319	} else if err != nil {
320		return fmt.Errorf("config file: could not open %s: %s", filename, err.Error())
321	} else {
322		// Make a decoder for it
323		jsonDecoder := json.NewDecoder(configFileReader)
324		err = jsonDecoder.Decode(configurable)
325		if err != nil {
326			return fmt.Errorf("config file: %s did not parse correctly: %s", filename, err.Error())
327		}
328	}
329
330	if Bool(configurable.GcovCoverage) && Bool(configurable.ClangCoverage) {
331		return fmt.Errorf("GcovCoverage and ClangCoverage cannot both be set")
332	}
333
334	configurable.Native_coverage = proptools.BoolPtr(
335		Bool(configurable.GcovCoverage) ||
336			Bool(configurable.ClangCoverage))
337
338	// when Platform_sdk_final is true (or PLATFORM_VERSION_CODENAME is REL), use Platform_sdk_version;
339	// if false (pre-released version, for example), use Platform_sdk_codename.
340	if Bool(configurable.Platform_sdk_final) {
341		if configurable.Platform_sdk_version != nil {
342			configurable.Platform_sdk_version_or_codename =
343				proptools.StringPtr(strconv.Itoa(*(configurable.Platform_sdk_version)))
344		} else {
345			return fmt.Errorf("Platform_sdk_version cannot be pointed by a NULL pointer")
346		}
347	} else {
348		configurable.Platform_sdk_version_or_codename =
349			proptools.StringPtr(String(configurable.Platform_sdk_codename))
350	}
351
352	return saveToBazelConfigFile(configurable, filepath.Dir(filename))
353}
354
355// atomically writes the config file in case two copies of soong_build are running simultaneously
356// (for example, docs generation and ninja manifest generation)
357func saveToConfigFile(config *productVariables, filename string) error {
358	data, err := json.MarshalIndent(&config, "", "    ")
359	if err != nil {
360		return fmt.Errorf("cannot marshal config data: %s", err.Error())
361	}
362
363	f, err := os.CreateTemp(filepath.Dir(filename), "config")
364	if err != nil {
365		return fmt.Errorf("cannot create empty config file %s: %s", filename, err.Error())
366	}
367	defer os.Remove(f.Name())
368	defer f.Close()
369
370	_, err = f.Write(data)
371	if err != nil {
372		return fmt.Errorf("default config file: %s could not be written: %s", filename, err.Error())
373	}
374
375	_, err = f.WriteString("\n")
376	if err != nil {
377		return fmt.Errorf("default config file: %s could not be written: %s", filename, err.Error())
378	}
379
380	f.Close()
381	os.Rename(f.Name(), filename)
382
383	return nil
384}
385
386func saveToBazelConfigFile(config *productVariables, outDir string) error {
387	dir := filepath.Join(outDir, bazel.SoongInjectionDirName, "product_config")
388	err := createDirIfNonexistent(dir, os.ModePerm)
389	if err != nil {
390		return fmt.Errorf("Could not create dir %s: %s", dir, err)
391	}
392
393	nonArchVariantProductVariables := []string{}
394	archVariantProductVariables := []string{}
395	p := variableProperties{}
396	t := reflect.TypeOf(p.Product_variables)
397	for i := 0; i < t.NumField(); i++ {
398		f := t.Field(i)
399		nonArchVariantProductVariables = append(nonArchVariantProductVariables, strings.ToLower(f.Name))
400		if proptools.HasTag(f, "android", "arch_variant") {
401			archVariantProductVariables = append(archVariantProductVariables, strings.ToLower(f.Name))
402		}
403	}
404
405	nonArchVariantProductVariablesJson := starlark_fmt.PrintStringList(nonArchVariantProductVariables, 0)
406	if err != nil {
407		return fmt.Errorf("cannot marshal product variable data: %s", err.Error())
408	}
409
410	archVariantProductVariablesJson := starlark_fmt.PrintStringList(archVariantProductVariables, 0)
411	if err != nil {
412		return fmt.Errorf("cannot marshal arch variant product variable data: %s", err.Error())
413	}
414
415	configJson, err := json.MarshalIndent(&config, "", "    ")
416	if err != nil {
417		return fmt.Errorf("cannot marshal config data: %s", err.Error())
418	}
419	// The backslashes need to be escaped because this text is going to be put
420	// inside a Starlark string literal.
421	configJson = bytes.ReplaceAll(configJson, []byte("\\"), []byte("\\\\"))
422
423	bzl := []string{
424		bazel.GeneratedBazelFileWarning,
425		fmt.Sprintf(`_product_vars = json.decode("""%s""")`, configJson),
426		fmt.Sprintf(`_product_var_constraints = %s`, nonArchVariantProductVariablesJson),
427		fmt.Sprintf(`_arch_variant_product_var_constraints = %s`, archVariantProductVariablesJson),
428		"\n", `
429product_vars = _product_vars
430
431# TODO(b/269577299) Remove these when everything switches over to loading them from product_variable_constants.bzl
432product_var_constraints = _product_var_constraints
433arch_variant_product_var_constraints = _arch_variant_product_var_constraints
434`,
435	}
436	err = pathtools.WriteFileIfChanged(filepath.Join(dir, "product_variables.bzl"),
437		[]byte(strings.Join(bzl, "\n")), 0644)
438	if err != nil {
439		return fmt.Errorf("Could not write .bzl config file %s", err)
440	}
441	err = pathtools.WriteFileIfChanged(filepath.Join(dir, "product_variable_constants.bzl"), []byte(fmt.Sprintf(`
442product_var_constraints = %s
443arch_variant_product_var_constraints = %s
444`, nonArchVariantProductVariablesJson, archVariantProductVariablesJson)), 0644)
445	if err != nil {
446		return fmt.Errorf("Could not write .bzl config file %s", err)
447	}
448	err = pathtools.WriteFileIfChanged(filepath.Join(dir, "BUILD"),
449		[]byte(bazel.GeneratedBazelFileWarning), 0644)
450	if err != nil {
451		return fmt.Errorf("Could not write BUILD config file %s", err)
452	}
453
454	return nil
455}
456
457// NullConfig returns a mostly empty Config for use by standalone tools like dexpreopt_gen that
458// use the android package.
459func NullConfig(outDir, soongOutDir string) Config {
460	return Config{
461		config: &config{
462			outDir:      outDir,
463			soongOutDir: soongOutDir,
464			fs:          pathtools.OsFs,
465		},
466	}
467}
468
469// NewConfig creates a new Config object. The srcDir argument specifies the path
470// to the root source directory. It also loads the config file, if found.
471func NewConfig(cmdArgs CmdArgs, availableEnv map[string]string) (Config, error) {
472	// Make a config with default options.
473	config := &config{
474		ProductVariablesFileName: filepath.Join(cmdArgs.SoongOutDir, productVariablesFileName),
475
476		env: availableEnv,
477
478		outDir:            cmdArgs.OutDir,
479		soongOutDir:       cmdArgs.SoongOutDir,
480		runGoTests:        cmdArgs.RunGoTests,
481		multilibConflicts: make(map[ArchType]bool),
482
483		moduleListFile:            cmdArgs.ModuleListFile,
484		fs:                        pathtools.NewOsFs(absSrcDir),
485		mixedBuildDisabledModules: make(map[string]struct{}),
486		mixedBuildEnabledModules:  make(map[string]struct{}),
487		bazelForceEnabledModules:  make(map[string]struct{}),
488
489		MultitreeBuild: cmdArgs.MultitreeBuild,
490		UseBazelProxy:  cmdArgs.UseBazelProxy,
491
492		buildFromTextStub: cmdArgs.BuildFromTextStub,
493	}
494
495	config.deviceConfig = &deviceConfig{
496		config: config,
497	}
498
499	// Soundness check of the build and source directories. This won't catch strange
500	// configurations with symlinks, but at least checks the obvious case.
501	absBuildDir, err := filepath.Abs(cmdArgs.SoongOutDir)
502	if err != nil {
503		return Config{}, err
504	}
505
506	absSrcDir, err := filepath.Abs(".")
507	if err != nil {
508		return Config{}, err
509	}
510
511	if strings.HasPrefix(absSrcDir, absBuildDir) {
512		return Config{}, fmt.Errorf("Build dir must not contain source directory")
513	}
514
515	// Load any configurable options from the configuration file
516	err = loadConfig(config)
517	if err != nil {
518		return Config{}, err
519	}
520
521	KatiEnabledMarkerFile := filepath.Join(cmdArgs.SoongOutDir, ".soong.kati_enabled")
522	if _, err := os.Stat(absolutePath(KatiEnabledMarkerFile)); err == nil {
523		config.katiEnabled = true
524	}
525
526	determineBuildOS(config)
527
528	// Sets up the map of target OSes to the finer grained compilation targets
529	// that are configured from the product variables.
530	targets, err := decodeTargetProductVariables(config)
531	if err != nil {
532		return Config{}, err
533	}
534
535	// Make the CommonOS OsType available for all products.
536	targets[CommonOS] = []Target{commonTargetMap[CommonOS.Name]}
537
538	var archConfig []archConfig
539	if config.NdkAbis() {
540		archConfig = getNdkAbisConfig()
541	} else if config.AmlAbis() {
542		archConfig = getAmlAbisConfig()
543	}
544
545	if archConfig != nil {
546		androidTargets, err := decodeAndroidArchSettings(archConfig)
547		if err != nil {
548			return Config{}, err
549		}
550		targets[Android] = androidTargets
551	}
552
553	multilib := make(map[string]bool)
554	for _, target := range targets[Android] {
555		if seen := multilib[target.Arch.ArchType.Multilib]; seen {
556			config.multilibConflicts[target.Arch.ArchType] = true
557		}
558		multilib[target.Arch.ArchType.Multilib] = true
559	}
560
561	// Map of OS to compilation targets.
562	config.Targets = targets
563
564	// Compilation targets for host tools.
565	config.BuildOSTarget = config.Targets[config.BuildOS][0]
566	config.BuildOSCommonTarget = getCommonTargets(config.Targets[config.BuildOS])[0]
567
568	// Compilation targets for Android.
569	if len(config.Targets[Android]) > 0 {
570		config.AndroidCommonTarget = getCommonTargets(config.Targets[Android])[0]
571		config.AndroidFirstDeviceTarget = FirstTarget(config.Targets[Android], "lib64", "lib32")[0]
572	}
573
574	setBuildMode := func(arg string, mode SoongBuildMode) {
575		if arg != "" {
576			if config.BuildMode != AnalysisNoBazel {
577				fmt.Fprintf(os.Stderr, "buildMode is already set, illegal argument: %s", arg)
578				os.Exit(1)
579			}
580			config.BuildMode = mode
581		}
582	}
583	setBazelMode := func(arg bool, argName string, mode SoongBuildMode) {
584		if arg {
585			if config.BuildMode != AnalysisNoBazel {
586				fmt.Fprintf(os.Stderr, "buildMode is already set, illegal argument: %s", argName)
587				os.Exit(1)
588			}
589			config.BuildMode = mode
590		}
591	}
592	setBuildMode(cmdArgs.SymlinkForestMarker, SymlinkForest)
593	setBuildMode(cmdArgs.Bp2buildMarker, Bp2build)
594	setBuildMode(cmdArgs.BazelQueryViewDir, GenerateQueryView)
595	setBuildMode(cmdArgs.BazelApiBp2buildDir, ApiBp2build)
596	setBuildMode(cmdArgs.ModuleGraphFile, GenerateModuleGraph)
597	setBuildMode(cmdArgs.DocFile, GenerateDocFile)
598	setBazelMode(cmdArgs.BazelModeDev, "--bazel-mode-dev", BazelDevMode)
599	setBazelMode(cmdArgs.BazelMode, "--bazel-mode", BazelProdMode)
600	setBazelMode(cmdArgs.BazelModeStaging, "--bazel-mode-staging", BazelStagingMode)
601
602	for _, module := range strings.Split(cmdArgs.BazelForceEnabledModules, ",") {
603		config.bazelForceEnabledModules[module] = struct{}{}
604	}
605	config.BazelContext, err = NewBazelContext(config)
606	config.Bp2buildPackageConfig = GetBp2BuildAllowList()
607
608	return Config{config}, err
609}
610
611// mockFileSystem replaces all reads with accesses to the provided map of
612// filenames to contents stored as a byte slice.
613func (c *config) mockFileSystem(bp string, fs map[string][]byte) {
614	mockFS := map[string][]byte{}
615
616	if _, exists := mockFS["Android.bp"]; !exists {
617		mockFS["Android.bp"] = []byte(bp)
618	}
619
620	for k, v := range fs {
621		mockFS[k] = v
622	}
623
624	// no module list file specified; find every file named Blueprints or Android.bp
625	pathsToParse := []string{}
626	for candidate := range mockFS {
627		base := filepath.Base(candidate)
628		if base == "Android.bp" {
629			pathsToParse = append(pathsToParse, candidate)
630		}
631	}
632	if len(pathsToParse) < 1 {
633		panic(fmt.Sprintf("No Blueprint or Android.bp files found in mock filesystem: %v\n", mockFS))
634	}
635	mockFS[blueprint.MockModuleListFile] = []byte(strings.Join(pathsToParse, "\n"))
636
637	c.fs = pathtools.MockFs(mockFS)
638	c.mockBpList = blueprint.MockModuleListFile
639}
640
641// TODO(b/265062549): Add a field to our collected (and uploaded) metrics which
642// describes a reason that we fell back to non-mixed builds.
643// Returns true if "Bazel builds" is enabled. In this mode, part of build
644// analysis is handled by Bazel.
645func (c *config) IsMixedBuildsEnabled() bool {
646	globalMixedBuildsSupport := c.Once(OnceKey{"globalMixedBuildsSupport"}, func() interface{} {
647		if c.productVariables.DeviceArch != nil && *c.productVariables.DeviceArch == "riscv64" {
648			return false
649		}
650		if c.IsEnvTrue("GLOBAL_THINLTO") {
651			return false
652		}
653		if len(c.productVariables.SanitizeHost) > 0 {
654			return false
655		}
656		if len(c.productVariables.SanitizeDevice) > 0 {
657			return false
658		}
659		if len(c.productVariables.SanitizeDeviceDiag) > 0 {
660			return false
661		}
662		if len(c.productVariables.SanitizeDeviceArch) > 0 {
663			return false
664		}
665		return true
666	}).(bool)
667
668	bazelModeEnabled := c.BuildMode == BazelProdMode || c.BuildMode == BazelDevMode || c.BuildMode == BazelStagingMode
669	return globalMixedBuildsSupport && bazelModeEnabled
670}
671
672func (c *config) SetAllowMissingDependencies() {
673	c.productVariables.Allow_missing_dependencies = proptools.BoolPtr(true)
674}
675
676// BlueprintToolLocation returns the directory containing build system tools
677// from Blueprint, like soong_zip and merge_zips.
678func (c *config) HostToolDir() string {
679	if c.KatiEnabled() {
680		return filepath.Join(c.outDir, "host", c.PrebuiltOS(), "bin")
681	} else {
682		return filepath.Join(c.soongOutDir, "host", c.PrebuiltOS(), "bin")
683	}
684}
685
686func (c *config) HostToolPath(ctx PathContext, tool string) Path {
687	path := pathForInstall(ctx, ctx.Config().BuildOS, ctx.Config().BuildArch, "bin", false, tool)
688	return path
689}
690
691func (c *config) HostJNIToolPath(ctx PathContext, lib string) Path {
692	ext := ".so"
693	if runtime.GOOS == "darwin" {
694		ext = ".dylib"
695	}
696	path := pathForInstall(ctx, ctx.Config().BuildOS, ctx.Config().BuildArch, "lib64", false, lib+ext)
697	return path
698}
699
700func (c *config) HostJavaToolPath(ctx PathContext, tool string) Path {
701	path := pathForInstall(ctx, ctx.Config().BuildOS, ctx.Config().BuildArch, "framework", false, tool)
702	return path
703}
704
705// PrebuiltOS returns the name of the host OS used in prebuilts directories.
706func (c *config) PrebuiltOS() string {
707	switch runtime.GOOS {
708	case "linux":
709		return "linux-x86"
710	case "darwin":
711		return "darwin-x86"
712	default:
713		panic("Unknown GOOS")
714	}
715}
716
717// GoRoot returns the path to the root directory of the Go toolchain.
718func (c *config) GoRoot() string {
719	return fmt.Sprintf("prebuilts/go/%s", c.PrebuiltOS())
720}
721
722// PrebuiltBuildTool returns the path to a tool in the prebuilts directory containing
723// checked-in tools, like Kati, Ninja or Toybox, for the current host OS.
724func (c *config) PrebuiltBuildTool(ctx PathContext, tool string) Path {
725	return PathForSource(ctx, "prebuilts/build-tools", c.PrebuiltOS(), "bin", tool)
726}
727
728// CpPreserveSymlinksFlags returns the host-specific flag for the cp(1) command
729// to preserve symlinks.
730func (c *config) CpPreserveSymlinksFlags() string {
731	switch runtime.GOOS {
732	case "darwin":
733		return "-R"
734	case "linux":
735		return "-d"
736	default:
737		return ""
738	}
739}
740
741func (c *config) Getenv(key string) string {
742	var val string
743	var exists bool
744	c.envLock.Lock()
745	defer c.envLock.Unlock()
746	if c.envDeps == nil {
747		c.envDeps = make(map[string]string)
748	}
749	if val, exists = c.envDeps[key]; !exists {
750		if c.envFrozen {
751			panic("Cannot access new environment variables after envdeps are frozen")
752		}
753		val, _ = c.env[key]
754		c.envDeps[key] = val
755	}
756	return val
757}
758
759func (c *config) GetenvWithDefault(key string, defaultValue string) string {
760	ret := c.Getenv(key)
761	if ret == "" {
762		return defaultValue
763	}
764	return ret
765}
766
767func (c *config) IsEnvTrue(key string) bool {
768	value := c.Getenv(key)
769	return value == "1" || value == "y" || value == "yes" || value == "on" || value == "true"
770}
771
772func (c *config) IsEnvFalse(key string) bool {
773	value := c.Getenv(key)
774	return value == "0" || value == "n" || value == "no" || value == "off" || value == "false"
775}
776
777// EnvDeps returns the environment variables this build depends on. The first
778// call to this function blocks future reads from the environment.
779func (c *config) EnvDeps() map[string]string {
780	c.envLock.Lock()
781	defer c.envLock.Unlock()
782	c.envFrozen = true
783	return c.envDeps
784}
785
786func (c *config) KatiEnabled() bool {
787	return c.katiEnabled
788}
789
790func (c *config) BuildId() string {
791	return String(c.productVariables.BuildId)
792}
793
794// BuildNumberFile returns the path to a text file containing metadata
795// representing the current build's number.
796//
797// Rules that want to reference the build number should read from this file
798// without depending on it. They will run whenever their other dependencies
799// require them to run and get the current build number. This ensures they don't
800// rebuild on every incremental build when the build number changes.
801func (c *config) BuildNumberFile(ctx PathContext) Path {
802	return PathForOutput(ctx, String(c.productVariables.BuildNumberFile))
803}
804
805// DeviceName returns the name of the current device target.
806// TODO: take an AndroidModuleContext to select the device name for multi-device builds
807func (c *config) DeviceName() string {
808	return *c.productVariables.DeviceName
809}
810
811// DeviceProduct returns the current product target. There could be multiple of
812// these per device type.
813//
814// NOTE: Do not base conditional logic on this value. It may break product inheritance.
815func (c *config) DeviceProduct() string {
816	return *c.productVariables.DeviceProduct
817}
818
819// HasDeviceProduct returns if the build has a product. A build will not
820// necessarily have a product when --skip-config is passed to soong, like it is
821// in prebuilts/build-tools/build-prebuilts.sh
822func (c *config) HasDeviceProduct() bool {
823	return c.productVariables.DeviceProduct != nil
824}
825
826func (c *config) DeviceResourceOverlays() []string {
827	return c.productVariables.DeviceResourceOverlays
828}
829
830func (c *config) ProductResourceOverlays() []string {
831	return c.productVariables.ProductResourceOverlays
832}
833
834func (c *config) PlatformVersionName() string {
835	return String(c.productVariables.Platform_version_name)
836}
837
838func (c *config) PlatformSdkVersion() ApiLevel {
839	return uncheckedFinalApiLevel(*c.productVariables.Platform_sdk_version)
840}
841
842func (c *config) RawPlatformSdkVersion() *int {
843	return c.productVariables.Platform_sdk_version
844}
845
846func (c *config) PlatformSdkFinal() bool {
847	return Bool(c.productVariables.Platform_sdk_final)
848}
849
850func (c *config) PlatformSdkCodename() string {
851	return String(c.productVariables.Platform_sdk_codename)
852}
853
854func (c *config) PlatformSdkExtensionVersion() int {
855	return *c.productVariables.Platform_sdk_extension_version
856}
857
858func (c *config) PlatformBaseSdkExtensionVersion() int {
859	return *c.productVariables.Platform_base_sdk_extension_version
860}
861
862func (c *config) PlatformSecurityPatch() string {
863	return String(c.productVariables.Platform_security_patch)
864}
865
866func (c *config) PlatformPreviewSdkVersion() string {
867	return String(c.productVariables.Platform_preview_sdk_version)
868}
869
870func (c *config) PlatformMinSupportedTargetSdkVersion() string {
871	return String(c.productVariables.Platform_min_supported_target_sdk_version)
872}
873
874func (c *config) PlatformBaseOS() string {
875	return String(c.productVariables.Platform_base_os)
876}
877
878func (c *config) PlatformVersionLastStable() string {
879	return String(c.productVariables.Platform_version_last_stable)
880}
881
882func (c *config) PlatformVersionKnownCodenames() string {
883	return String(c.productVariables.Platform_version_known_codenames)
884}
885
886func (c *config) MinSupportedSdkVersion() ApiLevel {
887	return uncheckedFinalApiLevel(21)
888}
889
890func (c *config) FinalApiLevels() []ApiLevel {
891	var levels []ApiLevel
892	for i := 1; i <= c.PlatformSdkVersion().FinalOrFutureInt(); i++ {
893		levels = append(levels, uncheckedFinalApiLevel(i))
894	}
895	return levels
896}
897
898func (c *config) PreviewApiLevels() []ApiLevel {
899	var levels []ApiLevel
900	for i, codename := range c.PlatformVersionActiveCodenames() {
901		levels = append(levels, ApiLevel{
902			value:     codename,
903			number:    i,
904			isPreview: true,
905		})
906	}
907	return levels
908}
909
910func (c *config) LatestPreviewApiLevel() ApiLevel {
911	level := NoneApiLevel
912	for _, l := range c.PreviewApiLevels() {
913		if l.GreaterThan(level) {
914			level = l
915		}
916	}
917	return level
918}
919
920func (c *config) AllSupportedApiLevels() []ApiLevel {
921	var levels []ApiLevel
922	levels = append(levels, c.FinalApiLevels()...)
923	return append(levels, c.PreviewApiLevels()...)
924}
925
926// DefaultAppTargetSdk returns the API level that platform apps are targeting.
927// This converts a codename to the exact ApiLevel it represents.
928func (c *config) DefaultAppTargetSdk(ctx EarlyModuleContext) ApiLevel {
929	// This logic is replicated in starlark, if changing logic here update starlark code too
930	// https://cs.android.com/android/platform/superproject/+/master:build/bazel/rules/common/api.bzl;l=72;drc=231c7e8c8038fd478a79eb68aa5b9f5c64e0e061
931	if Bool(c.productVariables.Platform_sdk_final) {
932		return c.PlatformSdkVersion()
933	}
934	codename := c.PlatformSdkCodename()
935	hostOnlyBuild := c.productVariables.DeviceArch == nil
936	if codename == "" {
937		// There are some host-only builds (those are invoked by build-prebuilts.sh) which
938		// don't set platform sdk codename. Platform sdk codename makes sense only when we
939		// are building the platform. So we don't enforce the below panic for the host-only
940		// builds.
941		if hostOnlyBuild {
942			return NoneApiLevel
943		}
944		panic("Platform_sdk_codename must be set")
945	}
946	if codename == "REL" {
947		panic("Platform_sdk_codename should not be REL when Platform_sdk_final is true")
948	}
949	return ApiLevelOrPanic(ctx, codename)
950}
951
952func (c *config) AppsDefaultVersionName() string {
953	return String(c.productVariables.AppsDefaultVersionName)
954}
955
956// Codenames that are active in the current lunch target.
957func (c *config) PlatformVersionActiveCodenames() []string {
958	return c.productVariables.Platform_version_active_codenames
959}
960
961// All unreleased codenames.
962func (c *config) PlatformVersionAllPreviewCodenames() []string {
963	return c.productVariables.Platform_version_all_preview_codenames
964}
965
966func (c *config) ProductAAPTConfig() []string {
967	return c.productVariables.AAPTConfig
968}
969
970func (c *config) ProductAAPTPreferredConfig() string {
971	return String(c.productVariables.AAPTPreferredConfig)
972}
973
974func (c *config) ProductAAPTCharacteristics() string {
975	return String(c.productVariables.AAPTCharacteristics)
976}
977
978func (c *config) ProductAAPTPrebuiltDPI() []string {
979	return c.productVariables.AAPTPrebuiltDPI
980}
981
982func (c *config) DefaultAppCertificateDir(ctx PathContext) SourcePath {
983	defaultCert := String(c.productVariables.DefaultAppCertificate)
984	if defaultCert != "" {
985		return PathForSource(ctx, filepath.Dir(defaultCert))
986	}
987	return PathForSource(ctx, "build/make/target/product/security")
988}
989
990func (c *config) DefaultAppCertificate(ctx PathContext) (pem, key SourcePath) {
991	defaultCert := String(c.productVariables.DefaultAppCertificate)
992	if defaultCert != "" {
993		return PathForSource(ctx, defaultCert+".x509.pem"), PathForSource(ctx, defaultCert+".pk8")
994	}
995	defaultDir := c.DefaultAppCertificateDir(ctx)
996	return defaultDir.Join(ctx, "testkey.x509.pem"), defaultDir.Join(ctx, "testkey.pk8")
997}
998
999func (c *config) ApexKeyDir(ctx ModuleContext) SourcePath {
1000	// TODO(b/121224311): define another variable such as TARGET_APEX_KEY_OVERRIDE
1001	defaultCert := String(c.productVariables.DefaultAppCertificate)
1002	if defaultCert == "" || filepath.Dir(defaultCert) == "build/make/target/product/security" {
1003		// When defaultCert is unset or is set to the testkeys path, use the APEX keys
1004		// that is under the module dir
1005		return pathForModuleSrc(ctx)
1006	}
1007	// If not, APEX keys are under the specified directory
1008	return PathForSource(ctx, filepath.Dir(defaultCert))
1009}
1010
1011// Certificate for the NetworkStack sepolicy context
1012func (c *config) MainlineSepolicyDevCertificatesDir(ctx ModuleContext) SourcePath {
1013	cert := String(c.productVariables.MainlineSepolicyDevCertificates)
1014	if cert != "" {
1015		return PathForSource(ctx, cert)
1016	}
1017	return c.DefaultAppCertificateDir(ctx)
1018}
1019
1020// AllowMissingDependencies configures Blueprint/Soong to not fail when modules
1021// are configured to depend on non-existent modules. Note that this does not
1022// affect missing input dependencies at the Ninja level.
1023func (c *config) AllowMissingDependencies() bool {
1024	return Bool(c.productVariables.Allow_missing_dependencies)
1025}
1026
1027// Returns true if a full platform source tree cannot be assumed.
1028func (c *config) UnbundledBuild() bool {
1029	return Bool(c.productVariables.Unbundled_build)
1030}
1031
1032// Returns true if building apps that aren't bundled with the platform.
1033// UnbundledBuild() is always true when this is true.
1034func (c *config) UnbundledBuildApps() bool {
1035	return len(c.productVariables.Unbundled_build_apps) > 0
1036}
1037
1038// Returns true if building image that aren't bundled with the platform.
1039// UnbundledBuild() is always true when this is true.
1040func (c *config) UnbundledBuildImage() bool {
1041	return Bool(c.productVariables.Unbundled_build_image)
1042}
1043
1044// Returns true if building modules against prebuilt SDKs.
1045func (c *config) AlwaysUsePrebuiltSdks() bool {
1046	return Bool(c.productVariables.Always_use_prebuilt_sdks)
1047}
1048
1049func (c *config) MinimizeJavaDebugInfo() bool {
1050	return Bool(c.productVariables.MinimizeJavaDebugInfo) && !Bool(c.productVariables.Eng)
1051}
1052
1053func (c *config) Debuggable() bool {
1054	return Bool(c.productVariables.Debuggable)
1055}
1056
1057func (c *config) Eng() bool {
1058	return Bool(c.productVariables.Eng)
1059}
1060
1061// DevicePrimaryArchType returns the ArchType for the first configured device architecture, or
1062// Common if there are no device architectures.
1063func (c *config) DevicePrimaryArchType() ArchType {
1064	if androidTargets := c.Targets[Android]; len(androidTargets) > 0 {
1065		return androidTargets[0].Arch.ArchType
1066	}
1067	return Common
1068}
1069
1070func (c *config) SanitizeHost() []string {
1071	return append([]string(nil), c.productVariables.SanitizeHost...)
1072}
1073
1074func (c *config) SanitizeDevice() []string {
1075	return append([]string(nil), c.productVariables.SanitizeDevice...)
1076}
1077
1078func (c *config) SanitizeDeviceDiag() []string {
1079	return append([]string(nil), c.productVariables.SanitizeDeviceDiag...)
1080}
1081
1082func (c *config) SanitizeDeviceArch() []string {
1083	return append([]string(nil), c.productVariables.SanitizeDeviceArch...)
1084}
1085
1086func (c *config) EnableCFI() bool {
1087	if c.productVariables.EnableCFI == nil {
1088		return true
1089	}
1090	return *c.productVariables.EnableCFI
1091}
1092
1093func (c *config) DisableScudo() bool {
1094	return Bool(c.productVariables.DisableScudo)
1095}
1096
1097func (c *config) Android64() bool {
1098	for _, t := range c.Targets[Android] {
1099		if t.Arch.ArchType.Multilib == "lib64" {
1100			return true
1101		}
1102	}
1103
1104	return false
1105}
1106
1107func (c *config) UseGoma() bool {
1108	return Bool(c.productVariables.UseGoma)
1109}
1110
1111func (c *config) UseRBE() bool {
1112	return Bool(c.productVariables.UseRBE)
1113}
1114
1115func (c *config) UseRBEJAVAC() bool {
1116	return Bool(c.productVariables.UseRBEJAVAC)
1117}
1118
1119func (c *config) UseRBER8() bool {
1120	return Bool(c.productVariables.UseRBER8)
1121}
1122
1123func (c *config) UseRBED8() bool {
1124	return Bool(c.productVariables.UseRBED8)
1125}
1126
1127func (c *config) UseRemoteBuild() bool {
1128	return c.UseGoma() || c.UseRBE()
1129}
1130
1131func (c *config) RunErrorProne() bool {
1132	return c.IsEnvTrue("RUN_ERROR_PRONE")
1133}
1134
1135// XrefCorpusName returns the Kythe cross-reference corpus name.
1136func (c *config) XrefCorpusName() string {
1137	return c.Getenv("XREF_CORPUS")
1138}
1139
1140// XrefCuEncoding returns the compilation unit encoding to use for Kythe code
1141// xrefs. Can be 'json' (default), 'proto' or 'all'.
1142func (c *config) XrefCuEncoding() string {
1143	if enc := c.Getenv("KYTHE_KZIP_ENCODING"); enc != "" {
1144		return enc
1145	}
1146	return "json"
1147}
1148
1149// XrefCuJavaSourceMax returns the maximum number of the Java source files
1150// in a single compilation unit
1151const xrefJavaSourceFileMaxDefault = "1000"
1152
1153func (c Config) XrefCuJavaSourceMax() string {
1154	v := c.Getenv("KYTHE_JAVA_SOURCE_BATCH_SIZE")
1155	if v == "" {
1156		return xrefJavaSourceFileMaxDefault
1157	}
1158	if _, err := strconv.ParseUint(v, 0, 0); err != nil {
1159		fmt.Fprintf(os.Stderr,
1160			"bad KYTHE_JAVA_SOURCE_BATCH_SIZE value: %s, will use %s",
1161			err, xrefJavaSourceFileMaxDefault)
1162		return xrefJavaSourceFileMaxDefault
1163	}
1164	return v
1165
1166}
1167
1168func (c *config) EmitXrefRules() bool {
1169	return c.XrefCorpusName() != ""
1170}
1171
1172func (c *config) ClangTidy() bool {
1173	return Bool(c.productVariables.ClangTidy)
1174}
1175
1176func (c *config) TidyChecks() string {
1177	if c.productVariables.TidyChecks == nil {
1178		return ""
1179	}
1180	return *c.productVariables.TidyChecks
1181}
1182
1183func (c *config) LibartImgHostBaseAddress() string {
1184	return "0x60000000"
1185}
1186
1187func (c *config) LibartImgDeviceBaseAddress() string {
1188	return "0x70000000"
1189}
1190
1191func (c *config) ArtUseReadBarrier() bool {
1192	return Bool(c.productVariables.ArtUseReadBarrier)
1193}
1194
1195// Enforce Runtime Resource Overlays for a module. RROs supersede static RROs,
1196// but some modules still depend on it.
1197//
1198// More info: https://source.android.com/devices/architecture/rros
1199func (c *config) EnforceRROForModule(name string) bool {
1200	enforceList := c.productVariables.EnforceRROTargets
1201
1202	if len(enforceList) > 0 {
1203		if InList("*", enforceList) {
1204			return true
1205		}
1206		return InList(name, enforceList)
1207	}
1208	return false
1209}
1210func (c *config) EnforceRROExcludedOverlay(path string) bool {
1211	excluded := c.productVariables.EnforceRROExcludedOverlays
1212	if len(excluded) > 0 {
1213		return HasAnyPrefix(path, excluded)
1214	}
1215	return false
1216}
1217
1218func (c *config) ExportedNamespaces() []string {
1219	return append([]string(nil), c.productVariables.NamespacesToExport...)
1220}
1221
1222func (c *config) SourceRootDirs() []string {
1223	return c.productVariables.SourceRootDirs
1224}
1225
1226func (c *config) IncludeTags() []string {
1227	return c.productVariables.IncludeTags
1228}
1229
1230func (c *config) HostStaticBinaries() bool {
1231	return Bool(c.productVariables.HostStaticBinaries)
1232}
1233
1234func (c *config) UncompressPrivAppDex() bool {
1235	return Bool(c.productVariables.UncompressPrivAppDex)
1236}
1237
1238func (c *config) ModulesLoadedByPrivilegedModules() []string {
1239	return c.productVariables.ModulesLoadedByPrivilegedModules
1240}
1241
1242// DexpreoptGlobalConfigPath returns the path to the dexpreopt.config file in
1243// the output directory, if it was created during the product configuration
1244// phase by Kati.
1245func (c *config) DexpreoptGlobalConfigPath(ctx PathContext) OptionalPath {
1246	if c.productVariables.DexpreoptGlobalConfig == nil {
1247		return OptionalPathForPath(nil)
1248	}
1249	return OptionalPathForPath(
1250		pathForBuildToolDep(ctx, *c.productVariables.DexpreoptGlobalConfig))
1251}
1252
1253// DexpreoptGlobalConfig returns the raw byte contents of the dexpreopt global
1254// configuration. Since the configuration file was created by Kati during
1255// product configuration (externally of soong_build), it's not tracked, so we
1256// also manually add a Ninja file dependency on the configuration file to the
1257// rule that creates the main build.ninja file. This ensures that build.ninja is
1258// regenerated correctly if dexpreopt.config changes.
1259func (c *config) DexpreoptGlobalConfig(ctx PathContext) ([]byte, error) {
1260	path := c.DexpreoptGlobalConfigPath(ctx)
1261	if !path.Valid() {
1262		return nil, nil
1263	}
1264	ctx.AddNinjaFileDeps(path.String())
1265	return os.ReadFile(absolutePath(path.String()))
1266}
1267
1268func (c *deviceConfig) WithDexpreopt() bool {
1269	return c.config.productVariables.WithDexpreopt
1270}
1271
1272func (c *config) FrameworksBaseDirExists(ctx PathGlobContext) bool {
1273	return ExistentPathForSource(ctx, "frameworks", "base", "Android.bp").Valid()
1274}
1275
1276func (c *config) VndkSnapshotBuildArtifacts() bool {
1277	return Bool(c.productVariables.VndkSnapshotBuildArtifacts)
1278}
1279
1280func (c *config) HasMultilibConflict(arch ArchType) bool {
1281	return c.multilibConflicts[arch]
1282}
1283
1284func (c *config) PrebuiltHiddenApiDir(_ PathContext) string {
1285	return String(c.productVariables.PrebuiltHiddenApiDir)
1286}
1287
1288func (c *config) BazelModulesForceEnabledByFlag() map[string]struct{} {
1289	return c.bazelForceEnabledModules
1290}
1291
1292func (c *deviceConfig) Arches() []Arch {
1293	var arches []Arch
1294	for _, target := range c.config.Targets[Android] {
1295		arches = append(arches, target.Arch)
1296	}
1297	return arches
1298}
1299
1300func (c *deviceConfig) BinderBitness() string {
1301	is32BitBinder := c.config.productVariables.Binder32bit
1302	if is32BitBinder != nil && *is32BitBinder {
1303		return "32"
1304	}
1305	return "64"
1306}
1307
1308func (c *deviceConfig) VendorPath() string {
1309	if c.config.productVariables.VendorPath != nil {
1310		return *c.config.productVariables.VendorPath
1311	}
1312	return "vendor"
1313}
1314
1315func (c *deviceConfig) VndkVersion() string {
1316	return String(c.config.productVariables.DeviceVndkVersion)
1317}
1318
1319func (c *deviceConfig) RecoverySnapshotVersion() string {
1320	return String(c.config.productVariables.RecoverySnapshotVersion)
1321}
1322
1323func (c *deviceConfig) CurrentApiLevelForVendorModules() string {
1324	return StringDefault(c.config.productVariables.DeviceCurrentApiLevelForVendorModules, "current")
1325}
1326
1327func (c *deviceConfig) PlatformVndkVersion() string {
1328	return String(c.config.productVariables.Platform_vndk_version)
1329}
1330
1331func (c *deviceConfig) ProductVndkVersion() string {
1332	return String(c.config.productVariables.ProductVndkVersion)
1333}
1334
1335func (c *deviceConfig) ExtraVndkVersions() []string {
1336	return c.config.productVariables.ExtraVndkVersions
1337}
1338
1339func (c *deviceConfig) VndkUseCoreVariant() bool {
1340	return Bool(c.config.productVariables.VndkUseCoreVariant)
1341}
1342
1343func (c *deviceConfig) SystemSdkVersions() []string {
1344	return c.config.productVariables.DeviceSystemSdkVersions
1345}
1346
1347func (c *deviceConfig) PlatformSystemSdkVersions() []string {
1348	return c.config.productVariables.Platform_systemsdk_versions
1349}
1350
1351func (c *deviceConfig) OdmPath() string {
1352	if c.config.productVariables.OdmPath != nil {
1353		return *c.config.productVariables.OdmPath
1354	}
1355	return "odm"
1356}
1357
1358func (c *deviceConfig) ProductPath() string {
1359	if c.config.productVariables.ProductPath != nil {
1360		return *c.config.productVariables.ProductPath
1361	}
1362	return "product"
1363}
1364
1365func (c *deviceConfig) SystemExtPath() string {
1366	if c.config.productVariables.SystemExtPath != nil {
1367		return *c.config.productVariables.SystemExtPath
1368	}
1369	return "system_ext"
1370}
1371
1372func (c *deviceConfig) BtConfigIncludeDir() string {
1373	return String(c.config.productVariables.BtConfigIncludeDir)
1374}
1375
1376func (c *deviceConfig) DeviceKernelHeaderDirs() []string {
1377	return c.config.productVariables.DeviceKernelHeaders
1378}
1379
1380// JavaCoverageEnabledForPath returns whether Java code coverage is enabled for
1381// path. Coverage is enabled by default when the product variable
1382// JavaCoveragePaths is empty. If JavaCoveragePaths is not empty, coverage is
1383// enabled for any path which is part of this variable (and not part of the
1384// JavaCoverageExcludePaths product variable). Value "*" in JavaCoveragePaths
1385// represents any path.
1386func (c *deviceConfig) JavaCoverageEnabledForPath(path string) bool {
1387	coverage := false
1388	if len(c.config.productVariables.JavaCoveragePaths) == 0 ||
1389		InList("*", c.config.productVariables.JavaCoveragePaths) ||
1390		HasAnyPrefix(path, c.config.productVariables.JavaCoveragePaths) {
1391		coverage = true
1392	}
1393	if coverage && len(c.config.productVariables.JavaCoverageExcludePaths) > 0 {
1394		if HasAnyPrefix(path, c.config.productVariables.JavaCoverageExcludePaths) {
1395			coverage = false
1396		}
1397	}
1398	return coverage
1399}
1400
1401// Returns true if gcov or clang coverage is enabled.
1402func (c *deviceConfig) NativeCoverageEnabled() bool {
1403	return Bool(c.config.productVariables.GcovCoverage) ||
1404		Bool(c.config.productVariables.ClangCoverage)
1405}
1406
1407func (c *deviceConfig) ClangCoverageEnabled() bool {
1408	return Bool(c.config.productVariables.ClangCoverage)
1409}
1410
1411func (c *deviceConfig) ClangCoverageContinuousMode() bool {
1412	return Bool(c.config.productVariables.ClangCoverageContinuousMode)
1413}
1414
1415func (c *deviceConfig) GcovCoverageEnabled() bool {
1416	return Bool(c.config.productVariables.GcovCoverage)
1417}
1418
1419// NativeCoverageEnabledForPath returns whether (GCOV- or Clang-based) native
1420// code coverage is enabled for path. By default, coverage is not enabled for a
1421// given path unless it is part of the NativeCoveragePaths product variable (and
1422// not part of the NativeCoverageExcludePaths product variable). Value "*" in
1423// NativeCoveragePaths represents any path.
1424func (c *deviceConfig) NativeCoverageEnabledForPath(path string) bool {
1425	coverage := false
1426	if len(c.config.productVariables.NativeCoveragePaths) > 0 {
1427		if InList("*", c.config.productVariables.NativeCoveragePaths) || HasAnyPrefix(path, c.config.productVariables.NativeCoveragePaths) {
1428			coverage = true
1429		}
1430	}
1431	if coverage && len(c.config.productVariables.NativeCoverageExcludePaths) > 0 {
1432		// Workaround coverage boot failure.
1433		// http://b/269981180
1434		if strings.HasPrefix(path, "external/protobuf") {
1435			coverage = false
1436		}
1437		if HasAnyPrefix(path, c.config.productVariables.NativeCoverageExcludePaths) {
1438			coverage = false
1439		}
1440	}
1441	return coverage
1442}
1443
1444func (c *deviceConfig) PgoAdditionalProfileDirs() []string {
1445	return c.config.productVariables.PgoAdditionalProfileDirs
1446}
1447
1448// AfdoProfile returns fully qualified path associated to the given module name
1449func (c *deviceConfig) AfdoProfile(name string) (*string, error) {
1450	for _, afdoProfile := range c.config.productVariables.AfdoProfiles {
1451		split := strings.Split(afdoProfile, ":")
1452		if len(split) != 3 {
1453			return nil, fmt.Errorf("AFDO_PROFILES has invalid value: %s. "+
1454				"The expected format is <module>:<fully-qualified-path-to-fdo_profile>", afdoProfile)
1455		}
1456		if split[0] == name {
1457			return proptools.StringPtr(strings.Join([]string{split[1], split[2]}, ":")), nil
1458		}
1459	}
1460	return nil, nil
1461}
1462
1463func (c *deviceConfig) VendorSepolicyDirs() []string {
1464	return c.config.productVariables.BoardVendorSepolicyDirs
1465}
1466
1467func (c *deviceConfig) OdmSepolicyDirs() []string {
1468	return c.config.productVariables.BoardOdmSepolicyDirs
1469}
1470
1471func (c *deviceConfig) SystemExtPublicSepolicyDirs() []string {
1472	return c.config.productVariables.SystemExtPublicSepolicyDirs
1473}
1474
1475func (c *deviceConfig) SystemExtPrivateSepolicyDirs() []string {
1476	return c.config.productVariables.SystemExtPrivateSepolicyDirs
1477}
1478
1479func (c *deviceConfig) SepolicyM4Defs() []string {
1480	return c.config.productVariables.BoardSepolicyM4Defs
1481}
1482
1483func (c *deviceConfig) OverrideManifestPackageNameFor(name string) (manifestName string, overridden bool) {
1484	return findOverrideValue(c.config.productVariables.ManifestPackageNameOverrides, name,
1485		"invalid override rule %q in PRODUCT_MANIFEST_PACKAGE_NAME_OVERRIDES should be <module_name>:<manifest_name>")
1486}
1487
1488func (c *deviceConfig) OverrideCertificateFor(name string) (certificatePath string, overridden bool) {
1489	return findOverrideValue(c.config.productVariables.CertificateOverrides, name,
1490		"invalid override rule %q in PRODUCT_CERTIFICATE_OVERRIDES should be <module_name>:<certificate_module_name>")
1491}
1492
1493func (c *deviceConfig) OverridePackageNameFor(name string) string {
1494	newName, overridden := findOverrideValue(
1495		c.config.productVariables.PackageNameOverrides,
1496		name,
1497		"invalid override rule %q in PRODUCT_PACKAGE_NAME_OVERRIDES should be <module_name>:<package_name>")
1498	if overridden {
1499		return newName
1500	}
1501	return name
1502}
1503
1504func findOverrideValue(overrides []string, name string, errorMsg string) (newValue string, overridden bool) {
1505	if overrides == nil || len(overrides) == 0 {
1506		return "", false
1507	}
1508	for _, o := range overrides {
1509		split := strings.Split(o, ":")
1510		if len(split) != 2 {
1511			// This shouldn't happen as this is first checked in make, but just in case.
1512			panic(fmt.Errorf(errorMsg, o))
1513		}
1514		if matchPattern(split[0], name) {
1515			return substPattern(split[0], split[1], name), true
1516		}
1517	}
1518	return "", false
1519}
1520
1521func (c *deviceConfig) ApexGlobalMinSdkVersionOverride() string {
1522	return String(c.config.productVariables.ApexGlobalMinSdkVersionOverride)
1523}
1524
1525func (c *config) IntegerOverflowDisabledForPath(path string) bool {
1526	if len(c.productVariables.IntegerOverflowExcludePaths) == 0 {
1527		return false
1528	}
1529	return HasAnyPrefix(path, c.productVariables.IntegerOverflowExcludePaths)
1530}
1531
1532func (c *config) CFIDisabledForPath(path string) bool {
1533	if len(c.productVariables.CFIExcludePaths) == 0 {
1534		return false
1535	}
1536	return HasAnyPrefix(path, c.productVariables.CFIExcludePaths)
1537}
1538
1539func (c *config) CFIEnabledForPath(path string) bool {
1540	if len(c.productVariables.CFIIncludePaths) == 0 {
1541		return false
1542	}
1543	return HasAnyPrefix(path, c.productVariables.CFIIncludePaths) && !c.CFIDisabledForPath(path)
1544}
1545
1546func (c *config) MemtagHeapDisabledForPath(path string) bool {
1547	if len(c.productVariables.MemtagHeapExcludePaths) == 0 {
1548		return false
1549	}
1550	return HasAnyPrefix(path, c.productVariables.MemtagHeapExcludePaths)
1551}
1552
1553func (c *config) MemtagHeapAsyncEnabledForPath(path string) bool {
1554	if len(c.productVariables.MemtagHeapAsyncIncludePaths) == 0 {
1555		return false
1556	}
1557	return HasAnyPrefix(path, c.productVariables.MemtagHeapAsyncIncludePaths) && !c.MemtagHeapDisabledForPath(path)
1558}
1559
1560func (c *config) MemtagHeapSyncEnabledForPath(path string) bool {
1561	if len(c.productVariables.MemtagHeapSyncIncludePaths) == 0 {
1562		return false
1563	}
1564	return HasAnyPrefix(path, c.productVariables.MemtagHeapSyncIncludePaths) && !c.MemtagHeapDisabledForPath(path)
1565}
1566
1567func (c *config) HWASanEnabledForPath(path string) bool {
1568	if len(c.productVariables.HWASanIncludePaths) == 0 {
1569		return false
1570	}
1571	return HasAnyPrefix(path, c.productVariables.HWASanIncludePaths)
1572}
1573
1574func (c *config) VendorConfig(name string) VendorConfig {
1575	return soongconfig.Config(c.productVariables.VendorVars[name])
1576}
1577
1578func (c *config) NdkAbis() bool {
1579	return Bool(c.productVariables.Ndk_abis)
1580}
1581
1582func (c *config) AmlAbis() bool {
1583	return Bool(c.productVariables.Aml_abis)
1584}
1585
1586func (c *config) FlattenApex() bool {
1587	return Bool(c.productVariables.Flatten_apex)
1588}
1589
1590func (c *config) ForceApexSymlinkOptimization() bool {
1591	return Bool(c.productVariables.ForceApexSymlinkOptimization)
1592}
1593
1594func (c *config) ApexCompressionEnabled() bool {
1595	return Bool(c.productVariables.CompressedApex) && !c.UnbundledBuildApps()
1596}
1597
1598func (c *config) ApexTrimEnabled() bool {
1599	return Bool(c.productVariables.TrimmedApex)
1600}
1601
1602func (c *config) EnforceSystemCertificate() bool {
1603	return Bool(c.productVariables.EnforceSystemCertificate)
1604}
1605
1606func (c *config) EnforceSystemCertificateAllowList() []string {
1607	return c.productVariables.EnforceSystemCertificateAllowList
1608}
1609
1610func (c *config) EnforceProductPartitionInterface() bool {
1611	return Bool(c.productVariables.EnforceProductPartitionInterface)
1612}
1613
1614func (c *config) EnforceInterPartitionJavaSdkLibrary() bool {
1615	return Bool(c.productVariables.EnforceInterPartitionJavaSdkLibrary)
1616}
1617
1618func (c *config) InterPartitionJavaLibraryAllowList() []string {
1619	return c.productVariables.InterPartitionJavaLibraryAllowList
1620}
1621
1622func (c *config) InstallExtraFlattenedApexes() bool {
1623	return Bool(c.productVariables.InstallExtraFlattenedApexes)
1624}
1625
1626func (c *config) ProductHiddenAPIStubs() []string {
1627	return c.productVariables.ProductHiddenAPIStubs
1628}
1629
1630func (c *config) ProductHiddenAPIStubsSystem() []string {
1631	return c.productVariables.ProductHiddenAPIStubsSystem
1632}
1633
1634func (c *config) ProductHiddenAPIStubsTest() []string {
1635	return c.productVariables.ProductHiddenAPIStubsTest
1636}
1637
1638func (c *deviceConfig) TargetFSConfigGen() []string {
1639	return c.config.productVariables.TargetFSConfigGen
1640}
1641
1642func (c *config) ProductPublicSepolicyDirs() []string {
1643	return c.productVariables.ProductPublicSepolicyDirs
1644}
1645
1646func (c *config) ProductPrivateSepolicyDirs() []string {
1647	return c.productVariables.ProductPrivateSepolicyDirs
1648}
1649
1650func (c *config) MissingUsesLibraries() []string {
1651	return c.productVariables.MissingUsesLibraries
1652}
1653
1654func (c *config) TargetMultitreeUpdateMeta() bool {
1655	return c.productVariables.MultitreeUpdateMeta
1656}
1657
1658func (c *deviceConfig) DeviceArch() string {
1659	return String(c.config.productVariables.DeviceArch)
1660}
1661
1662func (c *deviceConfig) DeviceArchVariant() string {
1663	return String(c.config.productVariables.DeviceArchVariant)
1664}
1665
1666func (c *deviceConfig) DeviceSecondaryArch() string {
1667	return String(c.config.productVariables.DeviceSecondaryArch)
1668}
1669
1670func (c *deviceConfig) DeviceSecondaryArchVariant() string {
1671	return String(c.config.productVariables.DeviceSecondaryArchVariant)
1672}
1673
1674func (c *deviceConfig) BoardUsesRecoveryAsBoot() bool {
1675	return Bool(c.config.productVariables.BoardUsesRecoveryAsBoot)
1676}
1677
1678func (c *deviceConfig) BoardKernelBinaries() []string {
1679	return c.config.productVariables.BoardKernelBinaries
1680}
1681
1682func (c *deviceConfig) BoardKernelModuleInterfaceVersions() []string {
1683	return c.config.productVariables.BoardKernelModuleInterfaceVersions
1684}
1685
1686func (c *deviceConfig) BoardMoveRecoveryResourcesToVendorBoot() bool {
1687	return Bool(c.config.productVariables.BoardMoveRecoveryResourcesToVendorBoot)
1688}
1689
1690func (c *deviceConfig) PlatformSepolicyVersion() string {
1691	return String(c.config.productVariables.PlatformSepolicyVersion)
1692}
1693
1694func (c *deviceConfig) TotSepolicyVersion() string {
1695	return String(c.config.productVariables.TotSepolicyVersion)
1696}
1697
1698func (c *deviceConfig) PlatformSepolicyCompatVersions() []string {
1699	return c.config.productVariables.PlatformSepolicyCompatVersions
1700}
1701
1702func (c *deviceConfig) BoardSepolicyVers() string {
1703	if ver := String(c.config.productVariables.BoardSepolicyVers); ver != "" {
1704		return ver
1705	}
1706	return c.PlatformSepolicyVersion()
1707}
1708
1709func (c *deviceConfig) BoardPlatVendorPolicy() []string {
1710	return c.config.productVariables.BoardPlatVendorPolicy
1711}
1712
1713func (c *deviceConfig) BoardReqdMaskPolicy() []string {
1714	return c.config.productVariables.BoardReqdMaskPolicy
1715}
1716
1717func (c *deviceConfig) BoardSystemExtPublicPrebuiltDirs() []string {
1718	return c.config.productVariables.BoardSystemExtPublicPrebuiltDirs
1719}
1720
1721func (c *deviceConfig) BoardSystemExtPrivatePrebuiltDirs() []string {
1722	return c.config.productVariables.BoardSystemExtPrivatePrebuiltDirs
1723}
1724
1725func (c *deviceConfig) BoardProductPublicPrebuiltDirs() []string {
1726	return c.config.productVariables.BoardProductPublicPrebuiltDirs
1727}
1728
1729func (c *deviceConfig) BoardProductPrivatePrebuiltDirs() []string {
1730	return c.config.productVariables.BoardProductPrivatePrebuiltDirs
1731}
1732
1733func (c *deviceConfig) SystemExtSepolicyPrebuiltApiDir() string {
1734	return String(c.config.productVariables.SystemExtSepolicyPrebuiltApiDir)
1735}
1736
1737func (c *deviceConfig) ProductSepolicyPrebuiltApiDir() string {
1738	return String(c.config.productVariables.ProductSepolicyPrebuiltApiDir)
1739}
1740
1741func (c *deviceConfig) IsPartnerTrebleSepolicyTestEnabled() bool {
1742	return c.SystemExtSepolicyPrebuiltApiDir() != "" || c.ProductSepolicyPrebuiltApiDir() != ""
1743}
1744
1745func (c *deviceConfig) DirectedVendorSnapshot() bool {
1746	return c.config.productVariables.DirectedVendorSnapshot
1747}
1748
1749func (c *deviceConfig) VendorSnapshotModules() map[string]bool {
1750	return c.config.productVariables.VendorSnapshotModules
1751}
1752
1753func (c *deviceConfig) DirectedRecoverySnapshot() bool {
1754	return c.config.productVariables.DirectedRecoverySnapshot
1755}
1756
1757func (c *deviceConfig) RecoverySnapshotModules() map[string]bool {
1758	return c.config.productVariables.RecoverySnapshotModules
1759}
1760
1761func createDirsMap(previous map[string]bool, dirs []string) (map[string]bool, error) {
1762	var ret = make(map[string]bool)
1763	for _, dir := range dirs {
1764		clean := filepath.Clean(dir)
1765		if previous[clean] || ret[clean] {
1766			return nil, fmt.Errorf("Duplicate entry %s", dir)
1767		}
1768		ret[clean] = true
1769	}
1770	return ret, nil
1771}
1772
1773func (c *deviceConfig) createDirsMapOnce(onceKey OnceKey, previous map[string]bool, dirs []string) map[string]bool {
1774	dirMap := c.Once(onceKey, func() interface{} {
1775		ret, err := createDirsMap(previous, dirs)
1776		if err != nil {
1777			panic(fmt.Errorf("%s: %w", onceKey.key, err))
1778		}
1779		return ret
1780	})
1781	if dirMap == nil {
1782		return nil
1783	}
1784	return dirMap.(map[string]bool)
1785}
1786
1787var vendorSnapshotDirsExcludedKey = NewOnceKey("VendorSnapshotDirsExcludedMap")
1788
1789func (c *deviceConfig) VendorSnapshotDirsExcludedMap() map[string]bool {
1790	return c.createDirsMapOnce(vendorSnapshotDirsExcludedKey, nil,
1791		c.config.productVariables.VendorSnapshotDirsExcluded)
1792}
1793
1794var vendorSnapshotDirsIncludedKey = NewOnceKey("VendorSnapshotDirsIncludedMap")
1795
1796func (c *deviceConfig) VendorSnapshotDirsIncludedMap() map[string]bool {
1797	excludedMap := c.VendorSnapshotDirsExcludedMap()
1798	return c.createDirsMapOnce(vendorSnapshotDirsIncludedKey, excludedMap,
1799		c.config.productVariables.VendorSnapshotDirsIncluded)
1800}
1801
1802var recoverySnapshotDirsExcludedKey = NewOnceKey("RecoverySnapshotDirsExcludedMap")
1803
1804func (c *deviceConfig) RecoverySnapshotDirsExcludedMap() map[string]bool {
1805	return c.createDirsMapOnce(recoverySnapshotDirsExcludedKey, nil,
1806		c.config.productVariables.RecoverySnapshotDirsExcluded)
1807}
1808
1809var recoverySnapshotDirsIncludedKey = NewOnceKey("RecoverySnapshotDirsIncludedMap")
1810
1811func (c *deviceConfig) RecoverySnapshotDirsIncludedMap() map[string]bool {
1812	excludedMap := c.RecoverySnapshotDirsExcludedMap()
1813	return c.createDirsMapOnce(recoverySnapshotDirsIncludedKey, excludedMap,
1814		c.config.productVariables.RecoverySnapshotDirsIncluded)
1815}
1816
1817func (c *deviceConfig) HostFakeSnapshotEnabled() bool {
1818	return c.config.productVariables.HostFakeSnapshotEnabled
1819}
1820
1821func (c *deviceConfig) ShippingApiLevel() ApiLevel {
1822	if c.config.productVariables.ShippingApiLevel == nil {
1823		return NoneApiLevel
1824	}
1825	apiLevel, _ := strconv.Atoi(*c.config.productVariables.ShippingApiLevel)
1826	return uncheckedFinalApiLevel(apiLevel)
1827}
1828
1829func (c *deviceConfig) BuildBrokenClangAsFlags() bool {
1830	return c.config.productVariables.BuildBrokenClangAsFlags
1831}
1832
1833func (c *deviceConfig) BuildBrokenClangCFlags() bool {
1834	return c.config.productVariables.BuildBrokenClangCFlags
1835}
1836
1837func (c *deviceConfig) BuildBrokenClangProperty() bool {
1838	return c.config.productVariables.BuildBrokenClangProperty
1839}
1840
1841func (c *deviceConfig) BuildBrokenEnforceSyspropOwner() bool {
1842	return c.config.productVariables.BuildBrokenEnforceSyspropOwner
1843}
1844
1845func (c *deviceConfig) BuildBrokenTrebleSyspropNeverallow() bool {
1846	return c.config.productVariables.BuildBrokenTrebleSyspropNeverallow
1847}
1848
1849func (c *deviceConfig) BuildBrokenUsesSoongPython2Modules() bool {
1850	return c.config.productVariables.BuildBrokenUsesSoongPython2Modules
1851}
1852
1853func (c *deviceConfig) BuildDebugfsRestrictionsEnabled() bool {
1854	return c.config.productVariables.BuildDebugfsRestrictionsEnabled
1855}
1856
1857func (c *deviceConfig) BuildBrokenVendorPropertyNamespace() bool {
1858	return c.config.productVariables.BuildBrokenVendorPropertyNamespace
1859}
1860
1861func (c *deviceConfig) BuildBrokenInputDir(name string) bool {
1862	return InList(name, c.config.productVariables.BuildBrokenInputDirModules)
1863}
1864
1865func (c *deviceConfig) BuildBrokenDepfile() bool {
1866	return Bool(c.config.productVariables.BuildBrokenDepfile)
1867}
1868
1869func (c *deviceConfig) RequiresInsecureExecmemForSwiftshader() bool {
1870	return c.config.productVariables.RequiresInsecureExecmemForSwiftshader
1871}
1872
1873func (c *config) SelinuxIgnoreNeverallows() bool {
1874	return c.productVariables.SelinuxIgnoreNeverallows
1875}
1876
1877func (c *deviceConfig) SepolicySplit() bool {
1878	return c.config.productVariables.SepolicySplit
1879}
1880
1881func (c *deviceConfig) SepolicyFreezeTestExtraDirs() []string {
1882	return c.config.productVariables.SepolicyFreezeTestExtraDirs
1883}
1884
1885func (c *deviceConfig) SepolicyFreezeTestExtraPrebuiltDirs() []string {
1886	return c.config.productVariables.SepolicyFreezeTestExtraPrebuiltDirs
1887}
1888
1889func (c *deviceConfig) GenerateAidlNdkPlatformBackend() bool {
1890	return c.config.productVariables.GenerateAidlNdkPlatformBackend
1891}
1892
1893func (c *config) IgnorePrefer32OnDevice() bool {
1894	return c.productVariables.IgnorePrefer32OnDevice
1895}
1896
1897func (c *config) BootJars() []string {
1898	return c.Once(earlyBootJarsKey, func() interface{} {
1899		list := c.productVariables.BootJars.CopyOfJars()
1900		return append(list, c.productVariables.ApexBootJars.CopyOfJars()...)
1901	}).([]string)
1902}
1903
1904func (c *config) NonApexBootJars() ConfiguredJarList {
1905	return c.productVariables.BootJars
1906}
1907
1908func (c *config) ApexBootJars() ConfiguredJarList {
1909	return c.productVariables.ApexBootJars
1910}
1911
1912func (c *config) RBEWrapper() string {
1913	return c.GetenvWithDefault("RBE_WRAPPER", remoteexec.DefaultWrapperPath)
1914}
1915
1916// UseHostMusl returns true if the host target has been configured to build against musl libc.
1917func (c *config) UseHostMusl() bool {
1918	return Bool(c.productVariables.HostMusl)
1919}
1920
1921func (c *config) LogMixedBuild(ctx BaseModuleContext, useBazel bool) {
1922	moduleName := ctx.Module().Name()
1923	c.mixedBuildsLock.Lock()
1924	defer c.mixedBuildsLock.Unlock()
1925	if useBazel {
1926		c.mixedBuildEnabledModules[moduleName] = struct{}{}
1927	} else {
1928		c.mixedBuildDisabledModules[moduleName] = struct{}{}
1929	}
1930}
1931
1932// ApiSurfaces directory returns the source path inside the api_surfaces repo
1933// (relative to workspace root).
1934func (c *config) ApiSurfacesDir(s ApiSurface, version string) string {
1935	return filepath.Join(
1936		"build",
1937		"bazel",
1938		"api_surfaces",
1939		s.String(),
1940		version)
1941}
1942
1943func (c *config) BuildFromTextStub() bool {
1944	return c.buildFromTextStub
1945}
1946
1947func (c *config) SetBuildFromTextStub(b bool) {
1948	c.buildFromTextStub = b
1949}
1950func (c *config) AddForceEnabledModules(forceEnabled []string) {
1951	for _, forceEnabledModule := range forceEnabled {
1952		c.bazelForceEnabledModules[forceEnabledModule] = struct{}{}
1953	}
1954}
1955