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