config.go 51 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803
  1. // Copyright 2017 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. package build
  15. import (
  16. "context"
  17. "encoding/json"
  18. "errors"
  19. "fmt"
  20. "io/ioutil"
  21. "math/rand"
  22. "os"
  23. "os/exec"
  24. "path/filepath"
  25. "runtime"
  26. "strconv"
  27. "strings"
  28. "syscall"
  29. "time"
  30. "android/soong/shared"
  31. "google.golang.org/protobuf/proto"
  32. smpb "android/soong/ui/metrics/metrics_proto"
  33. )
  34. const (
  35. envConfigDir = "vendor/google/tools/soong_config"
  36. jsonSuffix = "json"
  37. configFetcher = "vendor/google/tools/soong/expconfigfetcher"
  38. envConfigFetchTimeout = 20 * time.Second
  39. )
  40. var (
  41. rbeRandPrefix int
  42. googleProdCredsExistCache bool
  43. )
  44. func init() {
  45. rand.Seed(time.Now().UnixNano())
  46. rbeRandPrefix = rand.Intn(1000)
  47. }
  48. type Config struct{ *configImpl }
  49. type configImpl struct {
  50. // Some targets that are implemented in soong_build
  51. // (bp2build, json-module-graph) are not here and have their own bits below.
  52. arguments []string
  53. goma bool
  54. environ *Environment
  55. distDir string
  56. buildDateTime string
  57. logsPrefix string
  58. // From the arguments
  59. parallel int
  60. keepGoing int
  61. verbose bool
  62. checkbuild bool
  63. dist bool
  64. jsonModuleGraph bool
  65. apiBp2build bool // Generate BUILD files for Soong modules that contribute APIs
  66. bp2build bool
  67. queryview bool
  68. reportMkMetrics bool // Collect and report mk2bp migration progress metrics.
  69. soongDocs bool
  70. multitreeBuild bool // This is a multitree build.
  71. skipConfig bool
  72. skipKati bool
  73. skipKatiNinja bool
  74. skipSoong bool
  75. skipNinja bool
  76. skipSoongTests bool
  77. searchApiDir bool // Scan the Android.bp files generated in out/api_surfaces
  78. skipMetricsUpload bool
  79. buildStartedTime int64 // For metrics-upload-only - manually specify a build-started time
  80. buildFromTextStub bool
  81. ensureAllowlistIntegrity bool // For CI builds - make sure modules are mixed-built
  82. bazelExitCode int32 // For b runs - necessary for updating NonZeroExit
  83. besId string // For b runs, to identify the BuildEventService logs
  84. // From the product config
  85. katiArgs []string
  86. ninjaArgs []string
  87. katiSuffix string
  88. targetDevice string
  89. targetDeviceDir string
  90. sandboxConfig *SandboxConfig
  91. // Autodetected
  92. totalRAM uint64
  93. brokenDupRules bool
  94. brokenUsesNetwork bool
  95. brokenNinjaEnvVars []string
  96. pathReplaced bool
  97. bazelProdMode bool
  98. bazelStagingMode bool
  99. // Set by multiproduct_kati
  100. emptyNinjaFile bool
  101. metricsUploader string
  102. bazelForceEnabledModules string
  103. includeTags []string
  104. sourceRootDirs []string
  105. // Data source to write ninja weight list
  106. ninjaWeightListSource NinjaWeightListSource
  107. }
  108. type NinjaWeightListSource uint
  109. const (
  110. // ninja doesn't use weight list.
  111. NOT_USED NinjaWeightListSource = iota
  112. // ninja uses weight list based on previous builds by ninja log
  113. NINJA_LOG
  114. // ninja thinks every task has the same weight.
  115. EVENLY_DISTRIBUTED
  116. // ninja uses an external custom weight list
  117. EXTERNAL_FILE
  118. // ninja uses a prioritized module list from Soong
  119. HINT_FROM_SOONG
  120. // If ninja log exists, use NINJA_LOG, if not, use HINT_FROM_SOONG instead.
  121. // We can assume it is an incremental build if ninja log exists.
  122. DEFAULT
  123. )
  124. const srcDirFileCheck = "build/soong/root.bp"
  125. var buildFiles = []string{"Android.mk", "Android.bp"}
  126. type BuildAction uint
  127. const (
  128. // Builds all of the modules and their dependencies of a specified directory, relative to the root
  129. // directory of the source tree.
  130. BUILD_MODULES_IN_A_DIRECTORY BuildAction = iota
  131. // Builds all of the modules and their dependencies of a list of specified directories. All specified
  132. // directories are relative to the root directory of the source tree.
  133. BUILD_MODULES_IN_DIRECTORIES
  134. // Build a list of specified modules. If none was specified, simply build the whole source tree.
  135. BUILD_MODULES
  136. )
  137. // checkTopDir validates that the current directory is at the root directory of the source tree.
  138. func checkTopDir(ctx Context) {
  139. if _, err := os.Stat(srcDirFileCheck); err != nil {
  140. if os.IsNotExist(err) {
  141. ctx.Fatalf("Current working directory must be the source tree. %q not found.", srcDirFileCheck)
  142. }
  143. ctx.Fatalln("Error verifying tree state:", err)
  144. }
  145. }
  146. // fetchEnvConfig optionally fetches a configuration file that can then subsequently be
  147. // loaded into Soong environment to control certain aspects of build behavior (e.g., enabling RBE).
  148. // If a configuration file already exists on disk, the fetch is run in the background
  149. // so as to NOT block the rest of the build execution.
  150. func fetchEnvConfig(ctx Context, config *configImpl, envConfigName string) error {
  151. configName := envConfigName + "." + jsonSuffix
  152. expConfigFetcher := &smpb.ExpConfigFetcher{Filename: &configName}
  153. defer func() {
  154. ctx.Metrics.ExpConfigFetcher(expConfigFetcher)
  155. }()
  156. if !config.GoogleProdCredsExist() {
  157. status := smpb.ExpConfigFetcher_MISSING_GCERT
  158. expConfigFetcher.Status = &status
  159. return nil
  160. }
  161. s, err := os.Stat(configFetcher)
  162. if err != nil {
  163. if os.IsNotExist(err) {
  164. return nil
  165. }
  166. return err
  167. }
  168. if s.Mode()&0111 == 0 {
  169. status := smpb.ExpConfigFetcher_ERROR
  170. expConfigFetcher.Status = &status
  171. return fmt.Errorf("configuration fetcher binary %v is not executable: %v", configFetcher, s.Mode())
  172. }
  173. configExists := false
  174. outConfigFilePath := filepath.Join(config.OutDir(), configName)
  175. if _, err := os.Stat(outConfigFilePath); err == nil {
  176. configExists = true
  177. }
  178. tCtx, cancel := context.WithTimeout(ctx, envConfigFetchTimeout)
  179. fetchStart := time.Now()
  180. cmd := exec.CommandContext(tCtx, configFetcher, "-output_config_dir", config.OutDir(),
  181. "-output_config_name", configName)
  182. if err := cmd.Start(); err != nil {
  183. status := smpb.ExpConfigFetcher_ERROR
  184. expConfigFetcher.Status = &status
  185. return err
  186. }
  187. fetchCfg := func() error {
  188. if err := cmd.Wait(); err != nil {
  189. status := smpb.ExpConfigFetcher_ERROR
  190. expConfigFetcher.Status = &status
  191. return err
  192. }
  193. fetchEnd := time.Now()
  194. expConfigFetcher.Micros = proto.Uint64(uint64(fetchEnd.Sub(fetchStart).Microseconds()))
  195. expConfigFetcher.Filename = proto.String(outConfigFilePath)
  196. if _, err := os.Stat(outConfigFilePath); err != nil {
  197. status := smpb.ExpConfigFetcher_NO_CONFIG
  198. expConfigFetcher.Status = &status
  199. return err
  200. }
  201. status := smpb.ExpConfigFetcher_CONFIG
  202. expConfigFetcher.Status = &status
  203. return nil
  204. }
  205. // If a config file does not exist, wait for the config file to be fetched. Otherwise
  206. // fetch the config file in the background and return immediately.
  207. if !configExists {
  208. defer cancel()
  209. return fetchCfg()
  210. }
  211. go func() {
  212. defer cancel()
  213. if err := fetchCfg(); err != nil {
  214. ctx.Verbosef("Failed to fetch config file %v: %v\n", configName, err)
  215. }
  216. }()
  217. return nil
  218. }
  219. func loadEnvConfig(ctx Context, config *configImpl, bc string) error {
  220. if bc == "" {
  221. return nil
  222. }
  223. configDirs := []string{
  224. config.OutDir(),
  225. os.Getenv("ANDROID_BUILD_ENVIRONMENT_CONFIG_DIR"),
  226. envConfigDir,
  227. }
  228. for _, dir := range configDirs {
  229. cfgFile := filepath.Join(os.Getenv("TOP"), dir, fmt.Sprintf("%s.%s", bc, jsonSuffix))
  230. envVarsJSON, err := ioutil.ReadFile(cfgFile)
  231. if err != nil {
  232. continue
  233. }
  234. ctx.Verbosef("Loading config file %v\n", cfgFile)
  235. var envVars map[string]map[string]string
  236. if err := json.Unmarshal(envVarsJSON, &envVars); err != nil {
  237. fmt.Fprintf(os.Stderr, "Env vars config file %s did not parse correctly: %s", cfgFile, err.Error())
  238. continue
  239. }
  240. for k, v := range envVars["env"] {
  241. if os.Getenv(k) != "" {
  242. continue
  243. }
  244. config.environ.Set(k, v)
  245. }
  246. ctx.Verbosef("Finished loading config file %v\n", cfgFile)
  247. break
  248. }
  249. return nil
  250. }
  251. func defaultBazelProdMode(cfg *configImpl) bool {
  252. // Environment flag to disable Bazel for users which experience
  253. // broken bazel-handled builds, or significant performance regressions.
  254. if cfg.IsBazelMixedBuildForceDisabled() {
  255. return false
  256. }
  257. // Darwin-host builds are currently untested with Bazel.
  258. if runtime.GOOS == "darwin" {
  259. return false
  260. }
  261. return true
  262. }
  263. func UploadOnlyConfig(ctx Context, args ...string) Config {
  264. ret := &configImpl{
  265. environ: OsEnvironment(),
  266. sandboxConfig: &SandboxConfig{},
  267. }
  268. ret.parseArgs(ctx, args)
  269. srcDir := absPath(ctx, ".")
  270. bc := os.Getenv("ANDROID_BUILD_ENVIRONMENT_CONFIG")
  271. if err := loadEnvConfig(ctx, ret, bc); err != nil {
  272. ctx.Fatalln("Failed to parse env config files: %v", err)
  273. }
  274. ret.metricsUploader = GetMetricsUploader(srcDir, ret.environ)
  275. return Config{ret}
  276. }
  277. func NewConfig(ctx Context, args ...string) Config {
  278. ret := &configImpl{
  279. environ: OsEnvironment(),
  280. sandboxConfig: &SandboxConfig{},
  281. ninjaWeightListSource: DEFAULT,
  282. }
  283. // Default matching ninja
  284. ret.parallel = runtime.NumCPU() + 2
  285. ret.keepGoing = 1
  286. ret.totalRAM = detectTotalRAM(ctx)
  287. ret.parseArgs(ctx, args)
  288. if ret.ninjaWeightListSource == HINT_FROM_SOONG {
  289. ret.environ.Set("SOONG_GENERATES_NINJA_HINT", "always")
  290. } else if ret.ninjaWeightListSource == DEFAULT {
  291. defaultNinjaWeightListSource := NINJA_LOG
  292. if _, err := os.Stat(filepath.Join(ret.OutDir(), ninjaLogFileName)); errors.Is(err, os.ErrNotExist) {
  293. ctx.Verboseln("$OUT/.ninja_log doesn't exist, use HINT_FROM_SOONG instead")
  294. defaultNinjaWeightListSource = HINT_FROM_SOONG
  295. } else {
  296. ctx.Verboseln("$OUT/.ninja_log exist, use NINJA_LOG")
  297. }
  298. ret.ninjaWeightListSource = defaultNinjaWeightListSource
  299. // soong_build generates ninja hint depending on ninja log existence.
  300. // Set it "depend" to avoid soong re-run due to env variable change.
  301. ret.environ.Set("SOONG_GENERATES_NINJA_HINT", "depend")
  302. }
  303. // Make sure OUT_DIR is set appropriately
  304. if outDir, ok := ret.environ.Get("OUT_DIR"); ok {
  305. ret.environ.Set("OUT_DIR", filepath.Clean(outDir))
  306. } else {
  307. outDir := "out"
  308. if baseDir, ok := ret.environ.Get("OUT_DIR_COMMON_BASE"); ok {
  309. if wd, err := os.Getwd(); err != nil {
  310. ctx.Fatalln("Failed to get working directory:", err)
  311. } else {
  312. outDir = filepath.Join(baseDir, filepath.Base(wd))
  313. }
  314. }
  315. ret.environ.Set("OUT_DIR", outDir)
  316. }
  317. // loadEnvConfig needs to know what the OUT_DIR is, so it should
  318. // be called after we determine the appropriate out directory.
  319. bc := os.Getenv("ANDROID_BUILD_ENVIRONMENT_CONFIG")
  320. if bc != "" {
  321. if err := fetchEnvConfig(ctx, ret, bc); err != nil {
  322. ctx.Verbosef("Failed to fetch config file: %v\n", err)
  323. }
  324. if err := loadEnvConfig(ctx, ret, bc); err != nil {
  325. ctx.Fatalln("Failed to parse env config files: %v", err)
  326. }
  327. }
  328. if distDir, ok := ret.environ.Get("DIST_DIR"); ok {
  329. ret.distDir = filepath.Clean(distDir)
  330. } else {
  331. ret.distDir = filepath.Join(ret.OutDir(), "dist")
  332. }
  333. if srcDirIsWritable, ok := ret.environ.Get("BUILD_BROKEN_SRC_DIR_IS_WRITABLE"); ok {
  334. ret.sandboxConfig.SetSrcDirIsRO(srcDirIsWritable == "false")
  335. }
  336. ret.environ.Unset(
  337. // We're already using it
  338. "USE_SOONG_UI",
  339. // We should never use GOROOT/GOPATH from the shell environment
  340. "GOROOT",
  341. "GOPATH",
  342. // These should only come from Soong, not the environment.
  343. "CLANG",
  344. "CLANG_CXX",
  345. "CCC_CC",
  346. "CCC_CXX",
  347. // Used by the goma compiler wrapper, but should only be set by
  348. // gomacc
  349. "GOMACC_PATH",
  350. // We handle this above
  351. "OUT_DIR_COMMON_BASE",
  352. // This is handled above too, and set for individual commands later
  353. "DIST_DIR",
  354. // Variables that have caused problems in the past
  355. "BASH_ENV",
  356. "CDPATH",
  357. "DISPLAY",
  358. "GREP_OPTIONS",
  359. "JAVAC",
  360. "NDK_ROOT",
  361. "POSIXLY_CORRECT",
  362. // Drop make flags
  363. "MAKEFLAGS",
  364. "MAKELEVEL",
  365. "MFLAGS",
  366. // Set in envsetup.sh, reset in makefiles
  367. "ANDROID_JAVA_TOOLCHAIN",
  368. // Set by envsetup.sh, but shouldn't be used inside the build because envsetup.sh is optional
  369. "ANDROID_BUILD_TOP",
  370. "ANDROID_HOST_OUT",
  371. "ANDROID_PRODUCT_OUT",
  372. "ANDROID_HOST_OUT_TESTCASES",
  373. "ANDROID_TARGET_OUT_TESTCASES",
  374. "ANDROID_TOOLCHAIN",
  375. "ANDROID_TOOLCHAIN_2ND_ARCH",
  376. "ANDROID_DEV_SCRIPTS",
  377. "ANDROID_EMULATOR_PREBUILTS",
  378. "ANDROID_PRE_BUILD_PATHS",
  379. )
  380. if ret.UseGoma() || ret.ForceUseGoma() {
  381. ctx.Println("Goma for Android has been deprecated and replaced with RBE. See go/rbe_for_android for instructions on how to use RBE.")
  382. ctx.Fatalln("USE_GOMA / FORCE_USE_GOMA flag is no longer supported.")
  383. }
  384. // Tell python not to spam the source tree with .pyc files.
  385. ret.environ.Set("PYTHONDONTWRITEBYTECODE", "1")
  386. tmpDir := absPath(ctx, ret.TempDir())
  387. ret.environ.Set("TMPDIR", tmpDir)
  388. // Always set ASAN_SYMBOLIZER_PATH so that ASAN-based tools can symbolize any crashes
  389. symbolizerPath := filepath.Join("prebuilts/clang/host", ret.HostPrebuiltTag(),
  390. "llvm-binutils-stable/llvm-symbolizer")
  391. ret.environ.Set("ASAN_SYMBOLIZER_PATH", absPath(ctx, symbolizerPath))
  392. // Precondition: the current directory is the top of the source tree
  393. checkTopDir(ctx)
  394. srcDir := absPath(ctx, ".")
  395. if strings.ContainsRune(srcDir, ' ') {
  396. ctx.Println("You are building in a directory whose absolute path contains a space character:")
  397. ctx.Println()
  398. ctx.Printf("%q\n", srcDir)
  399. ctx.Println()
  400. ctx.Fatalln("Directory names containing spaces are not supported")
  401. }
  402. ret.metricsUploader = GetMetricsUploader(srcDir, ret.environ)
  403. if outDir := ret.OutDir(); strings.ContainsRune(outDir, ' ') {
  404. ctx.Println("The absolute path of your output directory ($OUT_DIR) contains a space character:")
  405. ctx.Println()
  406. ctx.Printf("%q\n", outDir)
  407. ctx.Println()
  408. ctx.Fatalln("Directory names containing spaces are not supported")
  409. }
  410. if distDir := ret.RealDistDir(); strings.ContainsRune(distDir, ' ') {
  411. ctx.Println("The absolute path of your dist directory ($DIST_DIR) contains a space character:")
  412. ctx.Println()
  413. ctx.Printf("%q\n", distDir)
  414. ctx.Println()
  415. ctx.Fatalln("Directory names containing spaces are not supported")
  416. }
  417. // Configure Java-related variables, including adding it to $PATH
  418. java8Home := filepath.Join("prebuilts/jdk/jdk8", ret.HostPrebuiltTag())
  419. java9Home := filepath.Join("prebuilts/jdk/jdk9", ret.HostPrebuiltTag())
  420. java11Home := filepath.Join("prebuilts/jdk/jdk11", ret.HostPrebuiltTag())
  421. java17Home := filepath.Join("prebuilts/jdk/jdk17", ret.HostPrebuiltTag())
  422. javaHome := func() string {
  423. if override, ok := ret.environ.Get("OVERRIDE_ANDROID_JAVA_HOME"); ok {
  424. return override
  425. }
  426. if toolchain11, ok := ret.environ.Get("EXPERIMENTAL_USE_OPENJDK11_TOOLCHAIN"); ok && toolchain11 != "true" {
  427. ctx.Fatalln("The environment variable EXPERIMENTAL_USE_OPENJDK11_TOOLCHAIN is no longer supported. An OpenJDK 11 toolchain is now the global default.")
  428. }
  429. if toolchain17, ok := ret.environ.Get("EXPERIMENTAL_USE_OPENJDK17_TOOLCHAIN"); ok && toolchain17 != "true" {
  430. ctx.Fatalln("The environment variable EXPERIMENTAL_USE_OPENJDK17_TOOLCHAIN is no longer supported. An OpenJDK 17 toolchain is now the global default.")
  431. }
  432. return java17Home
  433. }()
  434. absJavaHome := absPath(ctx, javaHome)
  435. ret.configureLocale(ctx)
  436. newPath := []string{filepath.Join(absJavaHome, "bin")}
  437. if path, ok := ret.environ.Get("PATH"); ok && path != "" {
  438. newPath = append(newPath, path)
  439. }
  440. ret.environ.Unset("OVERRIDE_ANDROID_JAVA_HOME")
  441. ret.environ.Set("JAVA_HOME", absJavaHome)
  442. ret.environ.Set("ANDROID_JAVA_HOME", javaHome)
  443. ret.environ.Set("ANDROID_JAVA8_HOME", java8Home)
  444. ret.environ.Set("ANDROID_JAVA9_HOME", java9Home)
  445. ret.environ.Set("ANDROID_JAVA11_HOME", java11Home)
  446. ret.environ.Set("PATH", strings.Join(newPath, string(filepath.ListSeparator)))
  447. if ret.MultitreeBuild() {
  448. ret.environ.Set("MULTITREE_BUILD", "true")
  449. }
  450. outDir := ret.OutDir()
  451. buildDateTimeFile := filepath.Join(outDir, "build_date.txt")
  452. if buildDateTime, ok := ret.environ.Get("BUILD_DATETIME"); ok && buildDateTime != "" {
  453. ret.buildDateTime = buildDateTime
  454. } else {
  455. ret.buildDateTime = strconv.FormatInt(time.Now().Unix(), 10)
  456. }
  457. ret.environ.Set("BUILD_DATETIME_FILE", buildDateTimeFile)
  458. if ret.UseRBE() {
  459. for k, v := range getRBEVars(ctx, Config{ret}) {
  460. ret.environ.Set(k, v)
  461. }
  462. }
  463. if ret.BuildFromTextStub() {
  464. // TODO(b/271443071): support hidden api check for from-text stub build
  465. ret.environ.Set("UNSAFE_DISABLE_HIDDENAPI_FLAGS", "true")
  466. }
  467. bpd := ret.BazelMetricsDir()
  468. if err := os.RemoveAll(bpd); err != nil {
  469. ctx.Fatalf("Unable to remove bazel profile directory %q: %v", bpd, err)
  470. }
  471. c := Config{ret}
  472. storeConfigMetrics(ctx, c)
  473. return c
  474. }
  475. // NewBuildActionConfig returns a build configuration based on the build action. The arguments are
  476. // processed based on the build action and extracts any arguments that belongs to the build action.
  477. func NewBuildActionConfig(action BuildAction, dir string, ctx Context, args ...string) Config {
  478. return NewConfig(ctx, getConfigArgs(action, dir, ctx, args)...)
  479. }
  480. // storeConfigMetrics selects a set of configuration information and store in
  481. // the metrics system for further analysis.
  482. func storeConfigMetrics(ctx Context, config Config) {
  483. if ctx.Metrics == nil {
  484. return
  485. }
  486. ctx.Metrics.BuildConfig(buildConfig(config))
  487. s := &smpb.SystemResourceInfo{
  488. TotalPhysicalMemory: proto.Uint64(config.TotalRAM()),
  489. AvailableCpus: proto.Int32(int32(runtime.NumCPU())),
  490. }
  491. ctx.Metrics.SystemResourceInfo(s)
  492. }
  493. func getNinjaWeightListSourceInMetric(s NinjaWeightListSource) *smpb.BuildConfig_NinjaWeightListSource {
  494. switch s {
  495. case NINJA_LOG:
  496. return smpb.BuildConfig_NINJA_LOG.Enum()
  497. case EVENLY_DISTRIBUTED:
  498. return smpb.BuildConfig_EVENLY_DISTRIBUTED.Enum()
  499. case EXTERNAL_FILE:
  500. return smpb.BuildConfig_EXTERNAL_FILE.Enum()
  501. case HINT_FROM_SOONG:
  502. return smpb.BuildConfig_HINT_FROM_SOONG.Enum()
  503. default:
  504. return smpb.BuildConfig_NOT_USED.Enum()
  505. }
  506. }
  507. func buildConfig(config Config) *smpb.BuildConfig {
  508. c := &smpb.BuildConfig{
  509. ForceUseGoma: proto.Bool(config.ForceUseGoma()),
  510. UseGoma: proto.Bool(config.UseGoma()),
  511. UseRbe: proto.Bool(config.UseRBE()),
  512. BazelMixedBuild: proto.Bool(config.BazelBuildEnabled()),
  513. ForceDisableBazelMixedBuild: proto.Bool(config.IsBazelMixedBuildForceDisabled()),
  514. NinjaWeightListSource: getNinjaWeightListSourceInMetric(config.NinjaWeightListSource()),
  515. }
  516. c.Targets = append(c.Targets, config.arguments...)
  517. return c
  518. }
  519. // getConfigArgs processes the command arguments based on the build action and creates a set of new
  520. // arguments to be accepted by Config.
  521. func getConfigArgs(action BuildAction, dir string, ctx Context, args []string) []string {
  522. // The next block of code verifies that the current directory is the root directory of the source
  523. // tree. It then finds the relative path of dir based on the root directory of the source tree
  524. // and verify that dir is inside of the source tree.
  525. checkTopDir(ctx)
  526. topDir, err := os.Getwd()
  527. if err != nil {
  528. ctx.Fatalf("Error retrieving top directory: %v", err)
  529. }
  530. dir, err = filepath.EvalSymlinks(dir)
  531. if err != nil {
  532. ctx.Fatalf("Unable to evaluate symlink of %s: %v", dir, err)
  533. }
  534. dir, err = filepath.Abs(dir)
  535. if err != nil {
  536. ctx.Fatalf("Unable to find absolute path %s: %v", dir, err)
  537. }
  538. relDir, err := filepath.Rel(topDir, dir)
  539. if err != nil {
  540. ctx.Fatalf("Unable to find relative path %s of %s: %v", relDir, topDir, err)
  541. }
  542. // If there are ".." in the path, it's not in the source tree.
  543. if strings.Contains(relDir, "..") {
  544. ctx.Fatalf("Directory %s is not under the source tree %s", dir, topDir)
  545. }
  546. configArgs := args[:]
  547. // If the arguments contains GET-INSTALL-PATH, change the target name prefix from MODULES-IN- to
  548. // GET-INSTALL-PATH-IN- to extract the installation path instead of building the modules.
  549. targetNamePrefix := "MODULES-IN-"
  550. if inList("GET-INSTALL-PATH", configArgs) {
  551. targetNamePrefix = "GET-INSTALL-PATH-IN-"
  552. configArgs = removeFromList("GET-INSTALL-PATH", configArgs)
  553. }
  554. var targets []string
  555. switch action {
  556. case BUILD_MODULES:
  557. // No additional processing is required when building a list of specific modules or all modules.
  558. case BUILD_MODULES_IN_A_DIRECTORY:
  559. // If dir is the root source tree, all the modules are built of the source tree are built so
  560. // no need to find the build file.
  561. if topDir == dir {
  562. break
  563. }
  564. buildFile := findBuildFile(ctx, relDir)
  565. if buildFile == "" {
  566. ctx.Fatalf("Build file not found for %s directory", relDir)
  567. }
  568. targets = []string{convertToTarget(filepath.Dir(buildFile), targetNamePrefix)}
  569. case BUILD_MODULES_IN_DIRECTORIES:
  570. newConfigArgs, dirs := splitArgs(configArgs)
  571. configArgs = newConfigArgs
  572. targets = getTargetsFromDirs(ctx, relDir, dirs, targetNamePrefix)
  573. }
  574. // Tidy only override all other specified targets.
  575. tidyOnly := os.Getenv("WITH_TIDY_ONLY")
  576. if tidyOnly == "true" || tidyOnly == "1" {
  577. configArgs = append(configArgs, "tidy_only")
  578. } else {
  579. configArgs = append(configArgs, targets...)
  580. }
  581. return configArgs
  582. }
  583. // convertToTarget replaces "/" to "-" in dir and pre-append the targetNamePrefix to the target name.
  584. func convertToTarget(dir string, targetNamePrefix string) string {
  585. return targetNamePrefix + strings.ReplaceAll(dir, "/", "-")
  586. }
  587. // hasBuildFile returns true if dir contains an Android build file.
  588. func hasBuildFile(ctx Context, dir string) bool {
  589. for _, buildFile := range buildFiles {
  590. _, err := os.Stat(filepath.Join(dir, buildFile))
  591. if err == nil {
  592. return true
  593. }
  594. if !os.IsNotExist(err) {
  595. ctx.Fatalf("Error retrieving the build file stats: %v", err)
  596. }
  597. }
  598. return false
  599. }
  600. // findBuildFile finds a build file (makefile or blueprint file) by looking if there is a build file
  601. // in the current and any sub directory of dir. If a build file is not found, traverse the path
  602. // up by one directory and repeat again until either a build file is found or reached to the root
  603. // source tree. The returned filename of build file is "Android.mk". If one was not found, a blank
  604. // string is returned.
  605. func findBuildFile(ctx Context, dir string) string {
  606. // If the string is empty or ".", assume it is top directory of the source tree.
  607. if dir == "" || dir == "." {
  608. return ""
  609. }
  610. found := false
  611. for buildDir := dir; buildDir != "."; buildDir = filepath.Dir(buildDir) {
  612. err := filepath.Walk(buildDir, func(path string, info os.FileInfo, err error) error {
  613. if err != nil {
  614. return err
  615. }
  616. if found {
  617. return filepath.SkipDir
  618. }
  619. if info.IsDir() {
  620. return nil
  621. }
  622. for _, buildFile := range buildFiles {
  623. if info.Name() == buildFile {
  624. found = true
  625. return filepath.SkipDir
  626. }
  627. }
  628. return nil
  629. })
  630. if err != nil {
  631. ctx.Fatalf("Error finding Android build file: %v", err)
  632. }
  633. if found {
  634. return filepath.Join(buildDir, "Android.mk")
  635. }
  636. }
  637. return ""
  638. }
  639. // splitArgs iterates over the arguments list and splits into two lists: arguments and directories.
  640. func splitArgs(args []string) (newArgs []string, dirs []string) {
  641. specialArgs := map[string]bool{
  642. "showcommands": true,
  643. "snod": true,
  644. "dist": true,
  645. "checkbuild": true,
  646. }
  647. newArgs = []string{}
  648. dirs = []string{}
  649. for _, arg := range args {
  650. // It's a dash argument if it starts with "-" or it's a key=value pair, it's not a directory.
  651. if strings.IndexRune(arg, '-') == 0 || strings.IndexRune(arg, '=') != -1 {
  652. newArgs = append(newArgs, arg)
  653. continue
  654. }
  655. if _, ok := specialArgs[arg]; ok {
  656. newArgs = append(newArgs, arg)
  657. continue
  658. }
  659. dirs = append(dirs, arg)
  660. }
  661. return newArgs, dirs
  662. }
  663. // getTargetsFromDirs iterates over the dirs list and creates a list of targets to build. If a
  664. // directory from the dirs list does not exist, a fatal error is raised. relDir is related to the
  665. // source root tree where the build action command was invoked. Each directory is validated if the
  666. // build file can be found and follows the format "dir1:target1,target2,...". Target is optional.
  667. func getTargetsFromDirs(ctx Context, relDir string, dirs []string, targetNamePrefix string) (targets []string) {
  668. for _, dir := range dirs {
  669. // The directory may have specified specific modules to build. ":" is the separator to separate
  670. // the directory and the list of modules.
  671. s := strings.Split(dir, ":")
  672. l := len(s)
  673. if l > 2 { // more than one ":" was specified.
  674. ctx.Fatalf("%s not in proper directory:target1,target2,... format (\":\" was specified more than once)", dir)
  675. }
  676. dir = filepath.Join(relDir, s[0])
  677. if _, err := os.Stat(dir); err != nil {
  678. ctx.Fatalf("couldn't find directory %s", dir)
  679. }
  680. // Verify that if there are any targets specified after ":". Each target is separated by ",".
  681. var newTargets []string
  682. if l == 2 && s[1] != "" {
  683. newTargets = strings.Split(s[1], ",")
  684. if inList("", newTargets) {
  685. ctx.Fatalf("%s not in proper directory:target1,target2,... format", dir)
  686. }
  687. }
  688. // If there are specified targets to build in dir, an android build file must exist for the one
  689. // shot build. For the non-targets case, find the appropriate build file and build all the
  690. // modules in dir (or the closest one in the dir path).
  691. if len(newTargets) > 0 {
  692. if !hasBuildFile(ctx, dir) {
  693. ctx.Fatalf("Couldn't locate a build file from %s directory", dir)
  694. }
  695. } else {
  696. buildFile := findBuildFile(ctx, dir)
  697. if buildFile == "" {
  698. ctx.Fatalf("Build file not found for %s directory", dir)
  699. }
  700. newTargets = []string{convertToTarget(filepath.Dir(buildFile), targetNamePrefix)}
  701. }
  702. targets = append(targets, newTargets...)
  703. }
  704. return targets
  705. }
  706. func (c *configImpl) parseArgs(ctx Context, args []string) {
  707. for i := 0; i < len(args); i++ {
  708. arg := strings.TrimSpace(args[i])
  709. if arg == "showcommands" {
  710. c.verbose = true
  711. } else if arg == "--empty-ninja-file" {
  712. c.emptyNinjaFile = true
  713. } else if arg == "--skip-ninja" {
  714. c.skipNinja = true
  715. } else if arg == "--skip-make" {
  716. // TODO(ccross): deprecate this, it has confusing behaviors. It doesn't run kati,
  717. // but it does run a Kati ninja file if the .kati_enabled marker file was created
  718. // by a previous build.
  719. c.skipConfig = true
  720. c.skipKati = true
  721. } else if arg == "--soong-only" {
  722. c.skipKati = true
  723. c.skipKatiNinja = true
  724. } else if arg == "--config-only" {
  725. c.skipKati = true
  726. c.skipKatiNinja = true
  727. c.skipSoong = true
  728. } else if arg == "--skip-config" {
  729. c.skipConfig = true
  730. } else if arg == "--skip-soong-tests" {
  731. c.skipSoongTests = true
  732. } else if arg == "--skip-metrics-upload" {
  733. c.skipMetricsUpload = true
  734. } else if arg == "--mk-metrics" {
  735. c.reportMkMetrics = true
  736. } else if arg == "--multitree-build" {
  737. c.multitreeBuild = true
  738. } else if arg == "--bazel-mode" {
  739. c.bazelProdMode = true
  740. } else if arg == "--bazel-mode-staging" {
  741. c.bazelStagingMode = true
  742. } else if arg == "--search-api-dir" {
  743. c.searchApiDir = true
  744. } else if strings.HasPrefix(arg, "--ninja_weight_source=") {
  745. source := strings.TrimPrefix(arg, "--ninja_weight_source=")
  746. if source == "ninja_log" {
  747. c.ninjaWeightListSource = NINJA_LOG
  748. } else if source == "evenly_distributed" {
  749. c.ninjaWeightListSource = EVENLY_DISTRIBUTED
  750. } else if source == "not_used" {
  751. c.ninjaWeightListSource = NOT_USED
  752. } else if source == "soong" {
  753. c.ninjaWeightListSource = HINT_FROM_SOONG
  754. } else if strings.HasPrefix(source, "file,") {
  755. c.ninjaWeightListSource = EXTERNAL_FILE
  756. filePath := strings.TrimPrefix(source, "file,")
  757. err := validateNinjaWeightList(filePath)
  758. if err != nil {
  759. ctx.Fatalf("Malformed weight list from %s: %s", filePath, err)
  760. }
  761. _, err = copyFile(filePath, filepath.Join(c.OutDir(), ".ninja_weight_list"))
  762. if err != nil {
  763. ctx.Fatalf("Error to copy ninja weight list from %s: %s", filePath, err)
  764. }
  765. } else {
  766. ctx.Fatalf("unknown option for ninja_weight_source: %s", source)
  767. }
  768. } else if arg == "--build-from-text-stub" {
  769. c.buildFromTextStub = true
  770. } else if strings.HasPrefix(arg, "--build-command=") {
  771. buildCmd := strings.TrimPrefix(arg, "--build-command=")
  772. // remove quotations
  773. buildCmd = strings.TrimPrefix(buildCmd, "\"")
  774. buildCmd = strings.TrimSuffix(buildCmd, "\"")
  775. ctx.Metrics.SetBuildCommand([]string{buildCmd})
  776. } else if strings.HasPrefix(arg, "--bazel-force-enabled-modules=") {
  777. c.bazelForceEnabledModules = strings.TrimPrefix(arg, "--bazel-force-enabled-modules=")
  778. } else if strings.HasPrefix(arg, "--build-started-time-unix-millis=") {
  779. buildTimeStr := strings.TrimPrefix(arg, "--build-started-time-unix-millis=")
  780. val, err := strconv.ParseInt(buildTimeStr, 10, 64)
  781. if err == nil {
  782. c.buildStartedTime = val
  783. } else {
  784. ctx.Fatalf("Error parsing build-time-started-unix-millis", err)
  785. }
  786. } else if arg == "--ensure-allowlist-integrity" {
  787. c.ensureAllowlistIntegrity = true
  788. } else if strings.HasPrefix(arg, "--bazel-exit-code=") {
  789. bazelExitCodeStr := strings.TrimPrefix(arg, "--bazel-exit-code=")
  790. val, err := strconv.Atoi(bazelExitCodeStr)
  791. if err == nil {
  792. c.bazelExitCode = int32(val)
  793. } else {
  794. ctx.Fatalf("Error parsing bazel-exit-code", err)
  795. }
  796. } else if strings.HasPrefix(arg, "--bes-id=") {
  797. c.besId = strings.TrimPrefix(arg, "--bes-id=")
  798. } else if len(arg) > 0 && arg[0] == '-' {
  799. parseArgNum := func(def int) int {
  800. if len(arg) > 2 {
  801. p, err := strconv.ParseUint(arg[2:], 10, 31)
  802. if err != nil {
  803. ctx.Fatalf("Failed to parse %q: %v", arg, err)
  804. }
  805. return int(p)
  806. } else if i+1 < len(args) {
  807. p, err := strconv.ParseUint(args[i+1], 10, 31)
  808. if err == nil {
  809. i++
  810. return int(p)
  811. }
  812. }
  813. return def
  814. }
  815. if len(arg) > 1 && arg[1] == 'j' {
  816. c.parallel = parseArgNum(c.parallel)
  817. } else if len(arg) > 1 && arg[1] == 'k' {
  818. c.keepGoing = parseArgNum(0)
  819. } else {
  820. ctx.Fatalln("Unknown option:", arg)
  821. }
  822. } else if k, v, ok := decodeKeyValue(arg); ok && len(k) > 0 {
  823. if k == "OUT_DIR" {
  824. ctx.Fatalln("OUT_DIR may only be set in the environment, not as a command line option.")
  825. }
  826. c.environ.Set(k, v)
  827. } else if arg == "dist" {
  828. c.dist = true
  829. } else if arg == "json-module-graph" {
  830. c.jsonModuleGraph = true
  831. } else if arg == "bp2build" {
  832. c.bp2build = true
  833. } else if arg == "api_bp2build" {
  834. c.apiBp2build = true
  835. } else if arg == "queryview" {
  836. c.queryview = true
  837. } else if arg == "soong_docs" {
  838. c.soongDocs = true
  839. } else {
  840. if arg == "checkbuild" {
  841. c.checkbuild = true
  842. }
  843. c.arguments = append(c.arguments, arg)
  844. }
  845. }
  846. if (!c.bazelProdMode) && (!c.bazelStagingMode) {
  847. c.bazelProdMode = defaultBazelProdMode(c)
  848. }
  849. }
  850. func validateNinjaWeightList(weightListFilePath string) (err error) {
  851. data, err := os.ReadFile(weightListFilePath)
  852. if err != nil {
  853. return
  854. }
  855. lines := strings.Split(strings.TrimSpace(string(data)), "\n")
  856. for _, line := range lines {
  857. fields := strings.Split(line, ",")
  858. if len(fields) != 2 {
  859. return fmt.Errorf("wrong format, each line should have two fields, but '%s'", line)
  860. }
  861. _, err = strconv.Atoi(fields[1])
  862. if err != nil {
  863. return
  864. }
  865. }
  866. return
  867. }
  868. func (c *configImpl) configureLocale(ctx Context) {
  869. cmd := Command(ctx, Config{c}, "locale", "locale", "-a")
  870. output, err := cmd.Output()
  871. var locales []string
  872. if err == nil {
  873. locales = strings.Split(string(output), "\n")
  874. } else {
  875. // If we're unable to list the locales, let's assume en_US.UTF-8
  876. locales = []string{"en_US.UTF-8"}
  877. ctx.Verbosef("Failed to list locales (%q), falling back to %q", err, locales)
  878. }
  879. // gettext uses LANGUAGE, which is passed directly through
  880. // For LANG and LC_*, only preserve the evaluated version of
  881. // LC_MESSAGES
  882. userLang := ""
  883. if lc_all, ok := c.environ.Get("LC_ALL"); ok {
  884. userLang = lc_all
  885. } else if lc_messages, ok := c.environ.Get("LC_MESSAGES"); ok {
  886. userLang = lc_messages
  887. } else if lang, ok := c.environ.Get("LANG"); ok {
  888. userLang = lang
  889. }
  890. c.environ.UnsetWithPrefix("LC_")
  891. if userLang != "" {
  892. c.environ.Set("LC_MESSAGES", userLang)
  893. }
  894. // The for LANG, use C.UTF-8 if it exists (Debian currently, proposed
  895. // for others)
  896. if inList("C.UTF-8", locales) {
  897. c.environ.Set("LANG", "C.UTF-8")
  898. } else if inList("C.utf8", locales) {
  899. // These normalize to the same thing
  900. c.environ.Set("LANG", "C.UTF-8")
  901. } else if inList("en_US.UTF-8", locales) {
  902. c.environ.Set("LANG", "en_US.UTF-8")
  903. } else if inList("en_US.utf8", locales) {
  904. // These normalize to the same thing
  905. c.environ.Set("LANG", "en_US.UTF-8")
  906. } else {
  907. ctx.Fatalln("System doesn't support either C.UTF-8 or en_US.UTF-8")
  908. }
  909. }
  910. func (c *configImpl) Environment() *Environment {
  911. return c.environ
  912. }
  913. func (c *configImpl) Arguments() []string {
  914. return c.arguments
  915. }
  916. func (c *configImpl) SoongBuildInvocationNeeded() bool {
  917. if len(c.Arguments()) > 0 {
  918. // Explicit targets requested that are not special targets like b2pbuild
  919. // or the JSON module graph
  920. return true
  921. }
  922. if !c.JsonModuleGraph() && !c.Bp2Build() && !c.Queryview() && !c.SoongDocs() && !c.ApiBp2build() {
  923. // Command line was empty, the default Ninja target is built
  924. return true
  925. }
  926. // bp2build + dist may be used to dist bp2build logs but does not require SoongBuildInvocation
  927. if c.Dist() && !c.Bp2Build() {
  928. return true
  929. }
  930. // build.ninja doesn't need to be generated
  931. return false
  932. }
  933. func (c *configImpl) OutDir() string {
  934. if outDir, ok := c.environ.Get("OUT_DIR"); ok {
  935. return outDir
  936. }
  937. return "out"
  938. }
  939. func (c *configImpl) DistDir() string {
  940. return c.distDir
  941. }
  942. func (c *configImpl) RealDistDir() string {
  943. return c.distDir
  944. }
  945. func (c *configImpl) NinjaArgs() []string {
  946. if c.skipKati {
  947. return c.arguments
  948. }
  949. return c.ninjaArgs
  950. }
  951. func (c *configImpl) BazelOutDir() string {
  952. return filepath.Join(c.OutDir(), "bazel")
  953. }
  954. func (c *configImpl) bazelOutputBase() string {
  955. return filepath.Join(c.BazelOutDir(), "output")
  956. }
  957. func (c *configImpl) SoongOutDir() string {
  958. return filepath.Join(c.OutDir(), "soong")
  959. }
  960. func (c *configImpl) ApiSurfacesOutDir() string {
  961. return filepath.Join(c.OutDir(), "api_surfaces")
  962. }
  963. func (c *configImpl) PrebuiltOS() string {
  964. switch runtime.GOOS {
  965. case "linux":
  966. return "linux-x86"
  967. case "darwin":
  968. return "darwin-x86"
  969. default:
  970. panic("Unknown GOOS")
  971. }
  972. }
  973. func (c *configImpl) HostToolDir() string {
  974. if c.SkipKatiNinja() {
  975. return filepath.Join(c.SoongOutDir(), "host", c.PrebuiltOS(), "bin")
  976. } else {
  977. return filepath.Join(c.OutDir(), "host", c.PrebuiltOS(), "bin")
  978. }
  979. }
  980. func (c *configImpl) NamedGlobFile(name string) string {
  981. return shared.JoinPath(c.SoongOutDir(), "globs-"+name+".ninja")
  982. }
  983. func (c *configImpl) UsedEnvFile(tag string) string {
  984. if v, ok := c.environ.Get("TARGET_PRODUCT"); ok {
  985. return shared.JoinPath(c.SoongOutDir(), usedEnvFile+"."+v+"."+tag)
  986. }
  987. return shared.JoinPath(c.SoongOutDir(), usedEnvFile+"."+tag)
  988. }
  989. func (c *configImpl) Bp2BuildFilesMarkerFile() string {
  990. return shared.JoinPath(c.SoongOutDir(), "bp2build_files_marker")
  991. }
  992. func (c *configImpl) Bp2BuildWorkspaceMarkerFile() string {
  993. return shared.JoinPath(c.SoongOutDir(), "bp2build_workspace_marker")
  994. }
  995. func (c *configImpl) SoongDocsHtml() string {
  996. return shared.JoinPath(c.SoongOutDir(), "docs/soong_build.html")
  997. }
  998. func (c *configImpl) QueryviewMarkerFile() string {
  999. return shared.JoinPath(c.SoongOutDir(), "queryview.marker")
  1000. }
  1001. func (c *configImpl) ApiBp2buildMarkerFile() string {
  1002. return shared.JoinPath(c.SoongOutDir(), "api_bp2build.marker")
  1003. }
  1004. func (c *configImpl) ModuleGraphFile() string {
  1005. return shared.JoinPath(c.SoongOutDir(), "module-graph.json")
  1006. }
  1007. func (c *configImpl) ModuleActionsFile() string {
  1008. return shared.JoinPath(c.SoongOutDir(), "module-actions.json")
  1009. }
  1010. func (c *configImpl) TempDir() string {
  1011. return shared.TempDirForOutDir(c.SoongOutDir())
  1012. }
  1013. func (c *configImpl) FileListDir() string {
  1014. return filepath.Join(c.OutDir(), ".module_paths")
  1015. }
  1016. func (c *configImpl) KatiSuffix() string {
  1017. if c.katiSuffix != "" {
  1018. return c.katiSuffix
  1019. }
  1020. panic("SetKatiSuffix has not been called")
  1021. }
  1022. // Checkbuild returns true if "checkbuild" was one of the build goals, which means that the
  1023. // user is interested in additional checks at the expense of build time.
  1024. func (c *configImpl) Checkbuild() bool {
  1025. return c.checkbuild
  1026. }
  1027. func (c *configImpl) Dist() bool {
  1028. return c.dist
  1029. }
  1030. func (c *configImpl) JsonModuleGraph() bool {
  1031. return c.jsonModuleGraph
  1032. }
  1033. func (c *configImpl) Bp2Build() bool {
  1034. return c.bp2build
  1035. }
  1036. func (c *configImpl) ApiBp2build() bool {
  1037. return c.apiBp2build
  1038. }
  1039. func (c *configImpl) Queryview() bool {
  1040. return c.queryview
  1041. }
  1042. func (c *configImpl) SoongDocs() bool {
  1043. return c.soongDocs
  1044. }
  1045. func (c *configImpl) IsVerbose() bool {
  1046. return c.verbose
  1047. }
  1048. func (c *configImpl) MultitreeBuild() bool {
  1049. return c.multitreeBuild
  1050. }
  1051. func (c *configImpl) NinjaWeightListSource() NinjaWeightListSource {
  1052. return c.ninjaWeightListSource
  1053. }
  1054. func (c *configImpl) SkipKati() bool {
  1055. return c.skipKati
  1056. }
  1057. func (c *configImpl) SkipKatiNinja() bool {
  1058. return c.skipKatiNinja
  1059. }
  1060. func (c *configImpl) SkipSoong() bool {
  1061. return c.skipSoong
  1062. }
  1063. func (c *configImpl) SkipNinja() bool {
  1064. return c.skipNinja
  1065. }
  1066. func (c *configImpl) SetSkipNinja(v bool) {
  1067. c.skipNinja = v
  1068. }
  1069. func (c *configImpl) SkipConfig() bool {
  1070. return c.skipConfig
  1071. }
  1072. func (c *configImpl) BuildFromTextStub() bool {
  1073. return c.buildFromTextStub
  1074. }
  1075. func (c *configImpl) TargetProduct() string {
  1076. if v, ok := c.environ.Get("TARGET_PRODUCT"); ok {
  1077. return v
  1078. }
  1079. panic("TARGET_PRODUCT is not defined")
  1080. }
  1081. func (c *configImpl) TargetProductOrErr() (string, error) {
  1082. if v, ok := c.environ.Get("TARGET_PRODUCT"); ok {
  1083. return v, nil
  1084. }
  1085. return "", fmt.Errorf("TARGET_PRODUCT is not defined")
  1086. }
  1087. func (c *configImpl) TargetDevice() string {
  1088. return c.targetDevice
  1089. }
  1090. func (c *configImpl) SetTargetDevice(device string) {
  1091. c.targetDevice = device
  1092. }
  1093. func (c *configImpl) TargetBuildVariant() string {
  1094. if v, ok := c.environ.Get("TARGET_BUILD_VARIANT"); ok {
  1095. return v
  1096. }
  1097. panic("TARGET_BUILD_VARIANT is not defined")
  1098. }
  1099. func (c *configImpl) KatiArgs() []string {
  1100. return c.katiArgs
  1101. }
  1102. func (c *configImpl) Parallel() int {
  1103. return c.parallel
  1104. }
  1105. func (c *configImpl) GetSourceRootDirs() []string {
  1106. return c.sourceRootDirs
  1107. }
  1108. func (c *configImpl) SetSourceRootDirs(i []string) {
  1109. c.sourceRootDirs = i
  1110. }
  1111. func (c *configImpl) GetIncludeTags() []string {
  1112. return c.includeTags
  1113. }
  1114. func (c *configImpl) SetIncludeTags(i []string) {
  1115. c.includeTags = i
  1116. }
  1117. func (c *configImpl) GetLogsPrefix() string {
  1118. return c.logsPrefix
  1119. }
  1120. func (c *configImpl) SetLogsPrefix(prefix string) {
  1121. c.logsPrefix = prefix
  1122. }
  1123. func (c *configImpl) HighmemParallel() int {
  1124. if i, ok := c.environ.GetInt("NINJA_HIGHMEM_NUM_JOBS"); ok {
  1125. return i
  1126. }
  1127. const minMemPerHighmemProcess = 8 * 1024 * 1024 * 1024
  1128. parallel := c.Parallel()
  1129. if c.UseRemoteBuild() {
  1130. // Ninja doesn't support nested pools, and when remote builds are enabled the total ninja parallelism
  1131. // is set very high (i.e. 500). Using a large value here would cause the total number of running jobs
  1132. // to be the sum of the sizes of the local and highmem pools, which will cause extra CPU contention.
  1133. // Return 1/16th of the size of the local pool, rounding up.
  1134. return (parallel + 15) / 16
  1135. } else if c.totalRAM == 0 {
  1136. // Couldn't detect the total RAM, don't restrict highmem processes.
  1137. return parallel
  1138. } else if c.totalRAM <= 16*1024*1024*1024 {
  1139. // Less than 16GB of ram, restrict to 1 highmem processes
  1140. return 1
  1141. } else if c.totalRAM <= 32*1024*1024*1024 {
  1142. // Less than 32GB of ram, restrict to 2 highmem processes
  1143. return 2
  1144. } else if p := int(c.totalRAM / minMemPerHighmemProcess); p < parallel {
  1145. // If less than 8GB total RAM per process, reduce the number of highmem processes
  1146. return p
  1147. }
  1148. // No restriction on highmem processes
  1149. return parallel
  1150. }
  1151. func (c *configImpl) TotalRAM() uint64 {
  1152. return c.totalRAM
  1153. }
  1154. // ForceUseGoma determines whether we should override Goma deprecation
  1155. // and use Goma for the current build or not.
  1156. func (c *configImpl) ForceUseGoma() bool {
  1157. if v, ok := c.environ.Get("FORCE_USE_GOMA"); ok {
  1158. v = strings.TrimSpace(v)
  1159. if v != "" && v != "false" {
  1160. return true
  1161. }
  1162. }
  1163. return false
  1164. }
  1165. func (c *configImpl) UseGoma() bool {
  1166. if v, ok := c.environ.Get("USE_GOMA"); ok {
  1167. v = strings.TrimSpace(v)
  1168. if v != "" && v != "false" {
  1169. return true
  1170. }
  1171. }
  1172. return false
  1173. }
  1174. func (c *configImpl) StartGoma() bool {
  1175. if !c.UseGoma() {
  1176. return false
  1177. }
  1178. if v, ok := c.environ.Get("NOSTART_GOMA"); ok {
  1179. v = strings.TrimSpace(v)
  1180. if v != "" && v != "false" {
  1181. return false
  1182. }
  1183. }
  1184. return true
  1185. }
  1186. func (c *configImpl) UseRBE() bool {
  1187. authType, _ := c.rbeAuth()
  1188. // Do not use RBE with prod credentials in scenarios when stubby doesn't exist, since
  1189. // its unlikely that we will be able to obtain necessary creds without stubby.
  1190. if !c.StubbyExists() && strings.Contains(authType, "use_google_prod_creds"){
  1191. return false
  1192. }
  1193. if v, ok := c.Environment().Get("USE_RBE"); ok {
  1194. v = strings.TrimSpace(v)
  1195. if v != "" && v != "false" {
  1196. return true
  1197. }
  1198. }
  1199. return false
  1200. }
  1201. func (c *configImpl) BazelBuildEnabled() bool {
  1202. return c.bazelProdMode || c.bazelStagingMode
  1203. }
  1204. func (c *configImpl) StartRBE() bool {
  1205. if !c.UseRBE() {
  1206. return false
  1207. }
  1208. if v, ok := c.environ.Get("NOSTART_RBE"); ok {
  1209. v = strings.TrimSpace(v)
  1210. if v != "" && v != "false" {
  1211. return false
  1212. }
  1213. }
  1214. return true
  1215. }
  1216. func (c *configImpl) rbeProxyLogsDir() string {
  1217. for _, f := range []string{"RBE_proxy_log_dir", "FLAG_output_dir"} {
  1218. if v, ok := c.environ.Get(f); ok {
  1219. return v
  1220. }
  1221. }
  1222. buildTmpDir := shared.TempDirForOutDir(c.SoongOutDir())
  1223. return filepath.Join(buildTmpDir, "rbe")
  1224. }
  1225. func (c *configImpl) rbeCacheDir() string {
  1226. for _, f := range []string{"RBE_cache_dir", "FLAG_cache_dir"} {
  1227. if v, ok := c.environ.Get(f); ok {
  1228. return v
  1229. }
  1230. }
  1231. return shared.JoinPath(c.SoongOutDir(), "rbe")
  1232. }
  1233. func (c *configImpl) shouldCleanupRBELogsDir() bool {
  1234. // Perform a log directory cleanup only when the log directory
  1235. // is auto created by the build rather than user-specified.
  1236. for _, f := range []string{"RBE_proxy_log_dir", "FLAG_output_dir"} {
  1237. if _, ok := c.environ.Get(f); ok {
  1238. return false
  1239. }
  1240. }
  1241. return true
  1242. }
  1243. func (c *configImpl) rbeExecRoot() string {
  1244. for _, f := range []string{"RBE_exec_root", "FLAG_exec_root"} {
  1245. if v, ok := c.environ.Get(f); ok {
  1246. return v
  1247. }
  1248. }
  1249. wd, err := os.Getwd()
  1250. if err != nil {
  1251. return ""
  1252. }
  1253. return wd
  1254. }
  1255. func (c *configImpl) rbeDir() string {
  1256. if v, ok := c.environ.Get("RBE_DIR"); ok {
  1257. return v
  1258. }
  1259. return "prebuilts/remoteexecution-client/live/"
  1260. }
  1261. func (c *configImpl) rbeReproxy() string {
  1262. for _, f := range []string{"RBE_re_proxy", "FLAG_re_proxy"} {
  1263. if v, ok := c.environ.Get(f); ok {
  1264. return v
  1265. }
  1266. }
  1267. return filepath.Join(c.rbeDir(), "reproxy")
  1268. }
  1269. func (c *configImpl) rbeAuth() (string, string) {
  1270. credFlags := []string{
  1271. "use_application_default_credentials",
  1272. "use_gce_credentials",
  1273. "credential_file",
  1274. "use_google_prod_creds",
  1275. }
  1276. for _, cf := range credFlags {
  1277. for _, f := range []string{"RBE_" + cf, "FLAG_" + cf} {
  1278. if v, ok := c.environ.Get(f); ok {
  1279. v = strings.TrimSpace(v)
  1280. if v != "" && v != "false" && v != "0" {
  1281. return "RBE_" + cf, v
  1282. }
  1283. }
  1284. }
  1285. }
  1286. return "RBE_use_application_default_credentials", "true"
  1287. }
  1288. func (c *configImpl) rbeSockAddr(dir string) (string, error) {
  1289. maxNameLen := len(syscall.RawSockaddrUnix{}.Path)
  1290. base := fmt.Sprintf("reproxy_%v.sock", rbeRandPrefix)
  1291. name := filepath.Join(dir, base)
  1292. if len(name) < maxNameLen {
  1293. return name, nil
  1294. }
  1295. name = filepath.Join("/tmp", base)
  1296. if len(name) < maxNameLen {
  1297. return name, nil
  1298. }
  1299. return "", fmt.Errorf("cannot generate a proxy socket address shorter than the limit of %v", maxNameLen)
  1300. }
  1301. // IsGooglerEnvironment returns true if the current build is running
  1302. // on a Google developer machine and false otherwise.
  1303. func (c *configImpl) IsGooglerEnvironment() bool {
  1304. cf := "ANDROID_BUILD_ENVIRONMENT_CONFIG"
  1305. if v, ok := c.environ.Get(cf); ok {
  1306. return v == "googler"
  1307. }
  1308. return false
  1309. }
  1310. // GoogleProdCredsExist determine whether credentials exist on the
  1311. // Googler machine to use remote execution.
  1312. func (c *configImpl) GoogleProdCredsExist() bool {
  1313. if googleProdCredsExistCache {
  1314. return googleProdCredsExistCache
  1315. }
  1316. if _, err := exec.Command("/usr/bin/gcertstatus", "-nocheck_ssh").Output(); err != nil {
  1317. return false
  1318. }
  1319. googleProdCredsExistCache = true
  1320. return true
  1321. }
  1322. // UseRemoteBuild indicates whether to use a remote build acceleration system
  1323. // to speed up the build.
  1324. func (c *configImpl) UseRemoteBuild() bool {
  1325. return c.UseGoma() || c.UseRBE()
  1326. }
  1327. // StubbyExists checks whether the stubby binary exists on the machine running
  1328. // the build.
  1329. func (c *configImpl) StubbyExists() bool {
  1330. if _, err := exec.LookPath("stubby"); err != nil {
  1331. return false
  1332. }
  1333. return true
  1334. }
  1335. // RemoteParallel controls how many remote jobs (i.e., commands which contain
  1336. // gomacc) are run in parallel. Note the parallelism of all other jobs is
  1337. // still limited by Parallel()
  1338. func (c *configImpl) RemoteParallel() int {
  1339. if !c.UseRemoteBuild() {
  1340. return 0
  1341. }
  1342. if i, ok := c.environ.GetInt("NINJA_REMOTE_NUM_JOBS"); ok {
  1343. return i
  1344. }
  1345. return 500
  1346. }
  1347. func (c *configImpl) SetKatiArgs(args []string) {
  1348. c.katiArgs = args
  1349. }
  1350. func (c *configImpl) SetNinjaArgs(args []string) {
  1351. c.ninjaArgs = args
  1352. }
  1353. func (c *configImpl) SetKatiSuffix(suffix string) {
  1354. c.katiSuffix = suffix
  1355. }
  1356. func (c *configImpl) LastKatiSuffixFile() string {
  1357. return filepath.Join(c.OutDir(), "last_kati_suffix")
  1358. }
  1359. func (c *configImpl) HasKatiSuffix() bool {
  1360. return c.katiSuffix != ""
  1361. }
  1362. func (c *configImpl) KatiEnvFile() string {
  1363. return filepath.Join(c.OutDir(), "env"+c.KatiSuffix()+".sh")
  1364. }
  1365. func (c *configImpl) KatiBuildNinjaFile() string {
  1366. return filepath.Join(c.OutDir(), "build"+c.KatiSuffix()+katiBuildSuffix+".ninja")
  1367. }
  1368. func (c *configImpl) KatiPackageNinjaFile() string {
  1369. return filepath.Join(c.OutDir(), "build"+c.KatiSuffix()+katiPackageSuffix+".ninja")
  1370. }
  1371. func (c *configImpl) SoongVarsFile() string {
  1372. targetProduct, err := c.TargetProductOrErr()
  1373. if err != nil {
  1374. return filepath.Join(c.SoongOutDir(), "soong.variables")
  1375. } else {
  1376. return filepath.Join(c.SoongOutDir(), "soong."+targetProduct+".variables")
  1377. }
  1378. }
  1379. func (c *configImpl) SoongNinjaFile() string {
  1380. targetProduct, err := c.TargetProductOrErr()
  1381. if err != nil {
  1382. return filepath.Join(c.SoongOutDir(), "build.ninja")
  1383. } else {
  1384. return filepath.Join(c.SoongOutDir(), "build."+targetProduct+".ninja")
  1385. }
  1386. }
  1387. func (c *configImpl) CombinedNinjaFile() string {
  1388. if c.katiSuffix == "" {
  1389. return filepath.Join(c.OutDir(), "combined.ninja")
  1390. }
  1391. return filepath.Join(c.OutDir(), "combined"+c.KatiSuffix()+".ninja")
  1392. }
  1393. func (c *configImpl) SoongAndroidMk() string {
  1394. return filepath.Join(c.SoongOutDir(), "Android-"+c.TargetProduct()+".mk")
  1395. }
  1396. func (c *configImpl) SoongMakeVarsMk() string {
  1397. return filepath.Join(c.SoongOutDir(), "make_vars-"+c.TargetProduct()+".mk")
  1398. }
  1399. func (c *configImpl) ProductOut() string {
  1400. return filepath.Join(c.OutDir(), "target", "product", c.TargetDevice())
  1401. }
  1402. func (c *configImpl) DevicePreviousProductConfig() string {
  1403. return filepath.Join(c.ProductOut(), "previous_build_config.mk")
  1404. }
  1405. func (c *configImpl) KatiPackageMkDir() string {
  1406. return filepath.Join(c.ProductOut(), "obj", "CONFIG", "kati_packaging")
  1407. }
  1408. func (c *configImpl) hostOutRoot() string {
  1409. return filepath.Join(c.OutDir(), "host")
  1410. }
  1411. func (c *configImpl) HostOut() string {
  1412. return filepath.Join(c.hostOutRoot(), c.HostPrebuiltTag())
  1413. }
  1414. // This probably needs to be multi-valued, so not exporting it for now
  1415. func (c *configImpl) hostCrossOut() string {
  1416. if runtime.GOOS == "linux" {
  1417. return filepath.Join(c.hostOutRoot(), "windows-x86")
  1418. } else {
  1419. return ""
  1420. }
  1421. }
  1422. func (c *configImpl) HostPrebuiltTag() string {
  1423. if runtime.GOOS == "linux" {
  1424. return "linux-x86"
  1425. } else if runtime.GOOS == "darwin" {
  1426. return "darwin-x86"
  1427. } else {
  1428. panic("Unsupported OS")
  1429. }
  1430. }
  1431. func (c *configImpl) PrebuiltBuildTool(name string) string {
  1432. if v, ok := c.environ.Get("SANITIZE_HOST"); ok {
  1433. if sanitize := strings.Fields(v); inList("address", sanitize) {
  1434. asan := filepath.Join("prebuilts/build-tools", c.HostPrebuiltTag(), "asan/bin", name)
  1435. if _, err := os.Stat(asan); err == nil {
  1436. return asan
  1437. }
  1438. }
  1439. }
  1440. return filepath.Join("prebuilts/build-tools", c.HostPrebuiltTag(), "bin", name)
  1441. }
  1442. func (c *configImpl) SetBuildBrokenDupRules(val bool) {
  1443. c.brokenDupRules = val
  1444. }
  1445. func (c *configImpl) BuildBrokenDupRules() bool {
  1446. return c.brokenDupRules
  1447. }
  1448. func (c *configImpl) SetBuildBrokenUsesNetwork(val bool) {
  1449. c.brokenUsesNetwork = val
  1450. }
  1451. func (c *configImpl) BuildBrokenUsesNetwork() bool {
  1452. return c.brokenUsesNetwork
  1453. }
  1454. func (c *configImpl) SetBuildBrokenNinjaUsesEnvVars(val []string) {
  1455. c.brokenNinjaEnvVars = val
  1456. }
  1457. func (c *configImpl) BuildBrokenNinjaUsesEnvVars() []string {
  1458. return c.brokenNinjaEnvVars
  1459. }
  1460. func (c *configImpl) SetTargetDeviceDir(dir string) {
  1461. c.targetDeviceDir = dir
  1462. }
  1463. func (c *configImpl) TargetDeviceDir() string {
  1464. return c.targetDeviceDir
  1465. }
  1466. func (c *configImpl) BuildDateTime() string {
  1467. return c.buildDateTime
  1468. }
  1469. func (c *configImpl) MetricsUploaderApp() string {
  1470. return c.metricsUploader
  1471. }
  1472. // LogsDir returns the absolute path to the logs directory where build log and
  1473. // metrics files are located. By default, the logs directory is the out
  1474. // directory. If the argument dist is specified, the logs directory
  1475. // is <dist_dir>/logs.
  1476. func (c *configImpl) LogsDir() string {
  1477. dir := c.OutDir()
  1478. if c.Dist() {
  1479. // Always write logs to the real dist dir, even if Bazel is using a rigged dist dir for other files
  1480. dir = filepath.Join(c.RealDistDir(), "logs")
  1481. }
  1482. absDir, err := filepath.Abs(dir)
  1483. if err != nil {
  1484. fmt.Fprintf(os.Stderr, "\nError making log dir '%s' absolute: %s\n", dir, err.Error())
  1485. os.Exit(1)
  1486. }
  1487. return absDir
  1488. }
  1489. // BazelMetricsDir returns the <logs dir>/bazel_metrics directory
  1490. // where the bazel profiles are located.
  1491. func (c *configImpl) BazelMetricsDir() string {
  1492. return filepath.Join(c.LogsDir(), "bazel_metrics")
  1493. }
  1494. // MkFileMetrics returns the file path for make-related metrics.
  1495. func (c *configImpl) MkMetrics() string {
  1496. return filepath.Join(c.LogsDir(), "mk_metrics.pb")
  1497. }
  1498. func (c *configImpl) SetEmptyNinjaFile(v bool) {
  1499. c.emptyNinjaFile = v
  1500. }
  1501. func (c *configImpl) EmptyNinjaFile() bool {
  1502. return c.emptyNinjaFile
  1503. }
  1504. func (c *configImpl) IsBazelMixedBuildForceDisabled() bool {
  1505. return c.Environment().IsEnvTrue("BUILD_BROKEN_DISABLE_BAZEL")
  1506. }
  1507. func (c *configImpl) IsPersistentBazelEnabled() bool {
  1508. return c.Environment().IsEnvTrue("USE_PERSISTENT_BAZEL")
  1509. }
  1510. // GetBazeliskBazelVersion returns the Bazel version to use for this build,
  1511. // or the empty string if the current canonical prod Bazel should be used.
  1512. // This environment variable should only be set to debug the build system.
  1513. // The Bazel version, if set, will be passed to Bazelisk, and Bazelisk will
  1514. // handle downloading and invoking the correct Bazel binary.
  1515. func (c *configImpl) GetBazeliskBazelVersion() string {
  1516. value, _ := c.Environment().Get("USE_BAZEL_VERSION")
  1517. return value
  1518. }
  1519. func (c *configImpl) BazelModulesForceEnabledByFlag() string {
  1520. return c.bazelForceEnabledModules
  1521. }
  1522. func (c *configImpl) SkipMetricsUpload() bool {
  1523. return c.skipMetricsUpload
  1524. }
  1525. func (c *configImpl) EnsureAllowlistIntegrity() bool {
  1526. return c.ensureAllowlistIntegrity
  1527. }
  1528. // Returns a Time object if one was passed via a command-line flag.
  1529. // Otherwise returns the passed default.
  1530. func (c *configImpl) BuildStartedTimeOrDefault(defaultTime time.Time) time.Time {
  1531. if c.buildStartedTime == 0 {
  1532. return defaultTime
  1533. }
  1534. return time.UnixMilli(c.buildStartedTime)
  1535. }
  1536. func (c *configImpl) BazelExitCode() int32 {
  1537. return c.bazelExitCode
  1538. }
  1539. func GetMetricsUploader(topDir string, env *Environment) string {
  1540. if p, ok := env.Get("METRICS_UPLOADER"); ok {
  1541. metricsUploader := filepath.Join(topDir, p)
  1542. if _, err := os.Stat(metricsUploader); err == nil {
  1543. return metricsUploader
  1544. }
  1545. }
  1546. return ""
  1547. }