config.go 51 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808
  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. // These alternate modes of running Soong do not use RBE / reclient.
  1188. if c.Bp2Build() || c.Queryview() || c.ApiBp2build() || c.JsonModuleGraph() {
  1189. return false
  1190. }
  1191. authType, _ := c.rbeAuth()
  1192. // Do not use RBE with prod credentials in scenarios when stubby doesn't exist, since
  1193. // its unlikely that we will be able to obtain necessary creds without stubby.
  1194. if !c.StubbyExists() && strings.Contains(authType, "use_google_prod_creds") {
  1195. return false
  1196. }
  1197. if v, ok := c.Environment().Get("USE_RBE"); ok {
  1198. v = strings.TrimSpace(v)
  1199. if v != "" && v != "false" {
  1200. return true
  1201. }
  1202. }
  1203. return false
  1204. }
  1205. func (c *configImpl) BazelBuildEnabled() bool {
  1206. return c.bazelProdMode || c.bazelStagingMode
  1207. }
  1208. func (c *configImpl) StartRBE() bool {
  1209. if !c.UseRBE() {
  1210. return false
  1211. }
  1212. if v, ok := c.environ.Get("NOSTART_RBE"); ok {
  1213. v = strings.TrimSpace(v)
  1214. if v != "" && v != "false" {
  1215. return false
  1216. }
  1217. }
  1218. return true
  1219. }
  1220. func (c *configImpl) rbeProxyLogsDir() string {
  1221. for _, f := range []string{"RBE_proxy_log_dir", "FLAG_output_dir"} {
  1222. if v, ok := c.environ.Get(f); ok {
  1223. return v
  1224. }
  1225. }
  1226. buildTmpDir := shared.TempDirForOutDir(c.SoongOutDir())
  1227. return filepath.Join(buildTmpDir, "rbe")
  1228. }
  1229. func (c *configImpl) rbeCacheDir() string {
  1230. for _, f := range []string{"RBE_cache_dir", "FLAG_cache_dir"} {
  1231. if v, ok := c.environ.Get(f); ok {
  1232. return v
  1233. }
  1234. }
  1235. return shared.JoinPath(c.SoongOutDir(), "rbe")
  1236. }
  1237. func (c *configImpl) shouldCleanupRBELogsDir() bool {
  1238. // Perform a log directory cleanup only when the log directory
  1239. // is auto created by the build rather than user-specified.
  1240. for _, f := range []string{"RBE_proxy_log_dir", "FLAG_output_dir"} {
  1241. if _, ok := c.environ.Get(f); ok {
  1242. return false
  1243. }
  1244. }
  1245. return true
  1246. }
  1247. func (c *configImpl) rbeExecRoot() string {
  1248. for _, f := range []string{"RBE_exec_root", "FLAG_exec_root"} {
  1249. if v, ok := c.environ.Get(f); ok {
  1250. return v
  1251. }
  1252. }
  1253. wd, err := os.Getwd()
  1254. if err != nil {
  1255. return ""
  1256. }
  1257. return wd
  1258. }
  1259. func (c *configImpl) rbeDir() string {
  1260. if v, ok := c.environ.Get("RBE_DIR"); ok {
  1261. return v
  1262. }
  1263. return "prebuilts/remoteexecution-client/live/"
  1264. }
  1265. func (c *configImpl) rbeReproxy() string {
  1266. for _, f := range []string{"RBE_re_proxy", "FLAG_re_proxy"} {
  1267. if v, ok := c.environ.Get(f); ok {
  1268. return v
  1269. }
  1270. }
  1271. return filepath.Join(c.rbeDir(), "reproxy")
  1272. }
  1273. func (c *configImpl) rbeAuth() (string, string) {
  1274. credFlags := []string{
  1275. "use_application_default_credentials",
  1276. "use_gce_credentials",
  1277. "credential_file",
  1278. "use_google_prod_creds",
  1279. }
  1280. for _, cf := range credFlags {
  1281. for _, f := range []string{"RBE_" + cf, "FLAG_" + cf} {
  1282. if v, ok := c.environ.Get(f); ok {
  1283. v = strings.TrimSpace(v)
  1284. if v != "" && v != "false" && v != "0" {
  1285. return "RBE_" + cf, v
  1286. }
  1287. }
  1288. }
  1289. }
  1290. return "RBE_use_application_default_credentials", "true"
  1291. }
  1292. func (c *configImpl) rbeSockAddr(dir string) (string, error) {
  1293. maxNameLen := len(syscall.RawSockaddrUnix{}.Path)
  1294. base := fmt.Sprintf("reproxy_%v.sock", rbeRandPrefix)
  1295. name := filepath.Join(dir, base)
  1296. if len(name) < maxNameLen {
  1297. return name, nil
  1298. }
  1299. name = filepath.Join("/tmp", base)
  1300. if len(name) < maxNameLen {
  1301. return name, nil
  1302. }
  1303. return "", fmt.Errorf("cannot generate a proxy socket address shorter than the limit of %v", maxNameLen)
  1304. }
  1305. // IsGooglerEnvironment returns true if the current build is running
  1306. // on a Google developer machine and false otherwise.
  1307. func (c *configImpl) IsGooglerEnvironment() bool {
  1308. cf := "ANDROID_BUILD_ENVIRONMENT_CONFIG"
  1309. if v, ok := c.environ.Get(cf); ok {
  1310. return v == "googler"
  1311. }
  1312. return false
  1313. }
  1314. // GoogleProdCredsExist determine whether credentials exist on the
  1315. // Googler machine to use remote execution.
  1316. func (c *configImpl) GoogleProdCredsExist() bool {
  1317. if googleProdCredsExistCache {
  1318. return googleProdCredsExistCache
  1319. }
  1320. if _, err := exec.Command("/usr/bin/gcertstatus", "-nocheck_ssh").Output(); err != nil {
  1321. return false
  1322. }
  1323. googleProdCredsExistCache = true
  1324. return true
  1325. }
  1326. // UseRemoteBuild indicates whether to use a remote build acceleration system
  1327. // to speed up the build.
  1328. func (c *configImpl) UseRemoteBuild() bool {
  1329. return c.UseGoma() || c.UseRBE()
  1330. }
  1331. // StubbyExists checks whether the stubby binary exists on the machine running
  1332. // the build.
  1333. func (c *configImpl) StubbyExists() bool {
  1334. if _, err := exec.LookPath("stubby"); err != nil {
  1335. return false
  1336. }
  1337. return true
  1338. }
  1339. // RemoteParallel controls how many remote jobs (i.e., commands which contain
  1340. // gomacc) are run in parallel. Note the parallelism of all other jobs is
  1341. // still limited by Parallel()
  1342. func (c *configImpl) RemoteParallel() int {
  1343. if !c.UseRemoteBuild() {
  1344. return 0
  1345. }
  1346. if i, ok := c.environ.GetInt("NINJA_REMOTE_NUM_JOBS"); ok {
  1347. return i
  1348. }
  1349. return 500
  1350. }
  1351. func (c *configImpl) SetKatiArgs(args []string) {
  1352. c.katiArgs = args
  1353. }
  1354. func (c *configImpl) SetNinjaArgs(args []string) {
  1355. c.ninjaArgs = args
  1356. }
  1357. func (c *configImpl) SetKatiSuffix(suffix string) {
  1358. c.katiSuffix = suffix
  1359. }
  1360. func (c *configImpl) LastKatiSuffixFile() string {
  1361. return filepath.Join(c.OutDir(), "last_kati_suffix")
  1362. }
  1363. func (c *configImpl) HasKatiSuffix() bool {
  1364. return c.katiSuffix != ""
  1365. }
  1366. func (c *configImpl) KatiEnvFile() string {
  1367. return filepath.Join(c.OutDir(), "env"+c.KatiSuffix()+".sh")
  1368. }
  1369. func (c *configImpl) KatiBuildNinjaFile() string {
  1370. return filepath.Join(c.OutDir(), "build"+c.KatiSuffix()+katiBuildSuffix+".ninja")
  1371. }
  1372. func (c *configImpl) KatiPackageNinjaFile() string {
  1373. return filepath.Join(c.OutDir(), "build"+c.KatiSuffix()+katiPackageSuffix+".ninja")
  1374. }
  1375. func (c *configImpl) SoongVarsFile() string {
  1376. targetProduct, err := c.TargetProductOrErr()
  1377. if err != nil {
  1378. return filepath.Join(c.SoongOutDir(), "soong.variables")
  1379. } else {
  1380. return filepath.Join(c.SoongOutDir(), "soong."+targetProduct+".variables")
  1381. }
  1382. }
  1383. func (c *configImpl) SoongNinjaFile() string {
  1384. targetProduct, err := c.TargetProductOrErr()
  1385. if err != nil {
  1386. return filepath.Join(c.SoongOutDir(), "build.ninja")
  1387. } else {
  1388. return filepath.Join(c.SoongOutDir(), "build."+targetProduct+".ninja")
  1389. }
  1390. }
  1391. func (c *configImpl) CombinedNinjaFile() string {
  1392. if c.katiSuffix == "" {
  1393. return filepath.Join(c.OutDir(), "combined.ninja")
  1394. }
  1395. return filepath.Join(c.OutDir(), "combined"+c.KatiSuffix()+".ninja")
  1396. }
  1397. func (c *configImpl) SoongAndroidMk() string {
  1398. return filepath.Join(c.SoongOutDir(), "Android-"+c.TargetProduct()+".mk")
  1399. }
  1400. func (c *configImpl) SoongMakeVarsMk() string {
  1401. return filepath.Join(c.SoongOutDir(), "make_vars-"+c.TargetProduct()+".mk")
  1402. }
  1403. func (c *configImpl) ProductOut() string {
  1404. return filepath.Join(c.OutDir(), "target", "product", c.TargetDevice())
  1405. }
  1406. func (c *configImpl) DevicePreviousProductConfig() string {
  1407. return filepath.Join(c.ProductOut(), "previous_build_config.mk")
  1408. }
  1409. func (c *configImpl) KatiPackageMkDir() string {
  1410. return filepath.Join(c.ProductOut(), "obj", "CONFIG", "kati_packaging")
  1411. }
  1412. func (c *configImpl) hostOutRoot() string {
  1413. return filepath.Join(c.OutDir(), "host")
  1414. }
  1415. func (c *configImpl) HostOut() string {
  1416. return filepath.Join(c.hostOutRoot(), c.HostPrebuiltTag())
  1417. }
  1418. // This probably needs to be multi-valued, so not exporting it for now
  1419. func (c *configImpl) hostCrossOut() string {
  1420. if runtime.GOOS == "linux" {
  1421. return filepath.Join(c.hostOutRoot(), "windows-x86")
  1422. } else {
  1423. return ""
  1424. }
  1425. }
  1426. func (c *configImpl) HostPrebuiltTag() string {
  1427. if runtime.GOOS == "linux" {
  1428. return "linux-x86"
  1429. } else if runtime.GOOS == "darwin" {
  1430. return "darwin-x86"
  1431. } else {
  1432. panic("Unsupported OS")
  1433. }
  1434. }
  1435. func (c *configImpl) PrebuiltBuildTool(name string) string {
  1436. if v, ok := c.environ.Get("SANITIZE_HOST"); ok {
  1437. if sanitize := strings.Fields(v); inList("address", sanitize) {
  1438. asan := filepath.Join("prebuilts/build-tools", c.HostPrebuiltTag(), "asan/bin", name)
  1439. if _, err := os.Stat(asan); err == nil {
  1440. return asan
  1441. }
  1442. }
  1443. }
  1444. return filepath.Join("prebuilts/build-tools", c.HostPrebuiltTag(), "bin", name)
  1445. }
  1446. func (c *configImpl) SetBuildBrokenDupRules(val bool) {
  1447. c.brokenDupRules = val
  1448. }
  1449. func (c *configImpl) BuildBrokenDupRules() bool {
  1450. return c.brokenDupRules
  1451. }
  1452. func (c *configImpl) SetBuildBrokenUsesNetwork(val bool) {
  1453. c.brokenUsesNetwork = val
  1454. }
  1455. func (c *configImpl) BuildBrokenUsesNetwork() bool {
  1456. return c.brokenUsesNetwork
  1457. }
  1458. func (c *configImpl) SetBuildBrokenNinjaUsesEnvVars(val []string) {
  1459. c.brokenNinjaEnvVars = val
  1460. }
  1461. func (c *configImpl) BuildBrokenNinjaUsesEnvVars() []string {
  1462. return c.brokenNinjaEnvVars
  1463. }
  1464. func (c *configImpl) SetTargetDeviceDir(dir string) {
  1465. c.targetDeviceDir = dir
  1466. }
  1467. func (c *configImpl) TargetDeviceDir() string {
  1468. return c.targetDeviceDir
  1469. }
  1470. func (c *configImpl) BuildDateTime() string {
  1471. return c.buildDateTime
  1472. }
  1473. func (c *configImpl) MetricsUploaderApp() string {
  1474. return c.metricsUploader
  1475. }
  1476. // LogsDir returns the absolute path to the logs directory where build log and
  1477. // metrics files are located. By default, the logs directory is the out
  1478. // directory. If the argument dist is specified, the logs directory
  1479. // is <dist_dir>/logs.
  1480. func (c *configImpl) LogsDir() string {
  1481. dir := c.OutDir()
  1482. if c.Dist() {
  1483. // Always write logs to the real dist dir, even if Bazel is using a rigged dist dir for other files
  1484. dir = filepath.Join(c.RealDistDir(), "logs")
  1485. }
  1486. absDir, err := filepath.Abs(dir)
  1487. if err != nil {
  1488. fmt.Fprintf(os.Stderr, "\nError making log dir '%s' absolute: %s\n", dir, err.Error())
  1489. os.Exit(1)
  1490. }
  1491. return absDir
  1492. }
  1493. // BazelMetricsDir returns the <logs dir>/bazel_metrics directory
  1494. // where the bazel profiles are located.
  1495. func (c *configImpl) BazelMetricsDir() string {
  1496. return filepath.Join(c.LogsDir(), "bazel_metrics")
  1497. }
  1498. // MkFileMetrics returns the file path for make-related metrics.
  1499. func (c *configImpl) MkMetrics() string {
  1500. return filepath.Join(c.LogsDir(), "mk_metrics.pb")
  1501. }
  1502. func (c *configImpl) SetEmptyNinjaFile(v bool) {
  1503. c.emptyNinjaFile = v
  1504. }
  1505. func (c *configImpl) EmptyNinjaFile() bool {
  1506. return c.emptyNinjaFile
  1507. }
  1508. func (c *configImpl) IsBazelMixedBuildForceDisabled() bool {
  1509. return c.Environment().IsEnvTrue("BUILD_BROKEN_DISABLE_BAZEL")
  1510. }
  1511. func (c *configImpl) IsPersistentBazelEnabled() bool {
  1512. return c.Environment().IsEnvTrue("USE_PERSISTENT_BAZEL")
  1513. }
  1514. // GetBazeliskBazelVersion returns the Bazel version to use for this build,
  1515. // or the empty string if the current canonical prod Bazel should be used.
  1516. // This environment variable should only be set to debug the build system.
  1517. // The Bazel version, if set, will be passed to Bazelisk, and Bazelisk will
  1518. // handle downloading and invoking the correct Bazel binary.
  1519. func (c *configImpl) GetBazeliskBazelVersion() string {
  1520. value, _ := c.Environment().Get("USE_BAZEL_VERSION")
  1521. return value
  1522. }
  1523. func (c *configImpl) BazelModulesForceEnabledByFlag() string {
  1524. return c.bazelForceEnabledModules
  1525. }
  1526. func (c *configImpl) SkipMetricsUpload() bool {
  1527. return c.skipMetricsUpload
  1528. }
  1529. func (c *configImpl) EnsureAllowlistIntegrity() bool {
  1530. return c.ensureAllowlistIntegrity
  1531. }
  1532. // Returns a Time object if one was passed via a command-line flag.
  1533. // Otherwise returns the passed default.
  1534. func (c *configImpl) BuildStartedTimeOrDefault(defaultTime time.Time) time.Time {
  1535. if c.buildStartedTime == 0 {
  1536. return defaultTime
  1537. }
  1538. return time.UnixMilli(c.buildStartedTime)
  1539. }
  1540. func (c *configImpl) BazelExitCode() int32 {
  1541. return c.bazelExitCode
  1542. }
  1543. func GetMetricsUploader(topDir string, env *Environment) string {
  1544. if p, ok := env.Get("METRICS_UPLOADER"); ok {
  1545. metricsUploader := filepath.Join(topDir, p)
  1546. if _, err := os.Stat(metricsUploader); err == nil {
  1547. return metricsUploader
  1548. }
  1549. }
  1550. return ""
  1551. }