blob: 3d7dc6ab5b104c61683e93900db52d9cc15ddcfa [file] [log] [blame]
Han Shen91445322013-03-20 13:43:31 -07001#!/usr/bin/python
Han Shen819f8622014-04-08 16:57:38 -07002"""Script to bootstrap the chroot using new toolchain.
3
4This script allows you to build/install a customized version of gcc/binutils,
5either by specifying branch or a local directory.
6
7This script must be executed outside chroot.
8
9Below is some typical usage -
10
11## Build gcc located at /local/gcc/dir and do a bootstrap using the new compiler
12## for the chromeos root. The script tries to find a valid chromeos tree all
13## the way up from your current working directory.
14./build_tool.py --gcc_dir=/loca/gcc/dir --bootstrap
15
16## Build binutils, using remote branch "mobile_toolchain_v17" and do a bootstrap
17## using the new binutils for the chromeos root. The script tries to find a
18## valid chromeos tree all the way up from your current working directory.
19./build_tool.py --binutils_branch=cros/mobile_toolchain_v17 \
20 --chromeos_root=/chromeos/dir --bootstrap
21
22## Same as above except only do it for board daisy - no bootstrapping involved.
23./build_tool.py --binutils_branch=cros/mobile_toolchain_v16 \
24 --chromeos_root=/chromeos/dir --board=daisy
25"""
Han Shen91445322013-03-20 13:43:31 -070026
27__author__ = 'shenhan@google.com (Han Shen)'
28
29import optparse
30import os
31import re
Han Shen91445322013-03-20 13:43:31 -070032import sys
33
Han Shen819f8622014-04-08 16:57:38 -070034import repo_to_repo
Han Shen91445322013-03-20 13:43:31 -070035from utils import command_executer
36from utils import logger
37from utils import misc
38
Han Shen819f8622014-04-08 16:57:38 -070039REPO_PATH_PATTERN = 'src/third_party/{0}'
40TEMP_BRANCH_NAME = 'internal_testing_branch_no_use'
41CHROMIUMOS_OVERLAY_PATH = 'src/third_party/chromiumos-overlay'
42EBUILD_PATH_PATTERN = 'src/third_party/chromiumos-overlay/sys-devel/{0}'
43
Han Shen91445322013-03-20 13:43:31 -070044
45class Bootstrapper(object):
Han Shen819f8622014-04-08 16:57:38 -070046 """Class that handles bootstrap process.
47 """
48
49 def __init__(self, chromeos_root, gcc_branch=None, gcc_dir=None,
50 binutils_branch=None, binutils_dir=None,
Han Shen03d30982014-06-12 11:22:29 -070051 board=None, disable_2nd_bootstrap=False,
52 setup_tool_ebuild_file_only=False):
Han Shen91445322013-03-20 13:43:31 -070053 self._chromeos_root = chromeos_root
Han Shen819f8622014-04-08 16:57:38 -070054
55 self._gcc_branch = gcc_branch
56 self._gcc_branch_tree = None
Han Shen91445322013-03-20 13:43:31 -070057 self._gcc_dir = gcc_dir
Han Shen91445322013-03-20 13:43:31 -070058 self._gcc_ebuild_file = None
59 self._gcc_ebuild_file_name = None
Han Shen819f8622014-04-08 16:57:38 -070060
61 self._binutils_branch = binutils_branch
62 self._binutils_branch_tree = None
63 self._binutils_dir = binutils_dir
64 self._binutils_ebuild_file = None
65 self._binutils_ebuild_file_name = None
66
67 self._setup_tool_ebuild_file_only = setup_tool_ebuild_file_only
68
69 self._ce = command_executer.GetCommandExecuter()
70 self._logger = logger.GetLogger()
71 self._board = board
Han Shen03d30982014-06-12 11:22:29 -070072 self._disable_2nd_bootstrap = disable_2nd_bootstrap
Han Shen819f8622014-04-08 16:57:38 -070073
74 def IsTreeSame(self, t1, t2):
75 diff = 'diff -qr -x .git -x .svn "{0}" "{1}"'.format(t1, t2)
76 if self._ce.RunCommand(diff, print_to_console=False) == 0:
77 self._logger.LogOutput('"{0}" and "{1}" are the same."'.format(t1, t2))
78 return True
79 self._logger.LogWarning('"{0}" and "{1}" are different."'.format(t1, t2))
80 return False
Han Shen91445322013-03-20 13:43:31 -070081
82 def SubmitToLocalBranch(self):
Han Shen819f8622014-04-08 16:57:38 -070083 """Copy source code to the chromium source tree and submit it locally."""
84 if self._gcc_dir:
85 if not self.SubmitToolToLocalBranch(
86 tool_name='gcc', tool_dir=self._gcc_dir):
87 return False
88 self._gcc_branch = TEMP_BRANCH_NAME
Han Shen91445322013-03-20 13:43:31 -070089
Han Shen819f8622014-04-08 16:57:38 -070090 if self._binutils_dir:
91 if not self.SubmitToolToLocalBranch(
92 tool_name='binutils', tool_dir=self._binutils_dir):
93 return False
94 self._binutils_branch = TEMP_BRANCH_NAME
95
96 return True
97
98 def SubmitToolToLocalBranch(self, tool_name, tool_dir):
99 """Copy the source code to local chromium source tree.
100
101 Args:
102 tool_name: either 'gcc' or 'binutils'
103 tool_dir: the tool source dir to be used
104 Returns:
105 True if all succeeded False otherwise.
106 """
107
108 # The next few steps creates an internal branch to sync with the tool dir
Han Shen91445322013-03-20 13:43:31 -0700109 # user provided.
Han Shen819f8622014-04-08 16:57:38 -0700110 chrome_tool_dir = self.GetChromeOsToolDir(tool_name)
Han Shen91445322013-03-20 13:43:31 -0700111
112 # 0. Test to see if git tree is free of local changes.
Han Shen819f8622014-04-08 16:57:38 -0700113 if not misc.IsGitTreeClean(chrome_tool_dir):
Han Shen91445322013-03-20 13:43:31 -0700114 self._logger.LogError(
Han Shen819f8622014-04-08 16:57:38 -0700115 'Git repository "{0}" not clean, aborted.'.format(chrome_tool_dir))
Han Shen91445322013-03-20 13:43:31 -0700116 return False
117
118 # 1. Checkout/create a (new) branch for testing.
Han Shen819f8622014-04-08 16:57:38 -0700119 command = 'cd "{0}" && git checkout -B {1}'.format(
120 chrome_tool_dir, TEMP_BRANCH_NAME)
Han Shen91445322013-03-20 13:43:31 -0700121 ret = self._ce.RunCommand(command)
122 if ret:
123 self._logger.LogError('Failed to create a temp branch for test, aborted.')
124 return False
125
Han Shen819f8622014-04-08 16:57:38 -0700126 if self.IsTreeSame(tool_dir, chrome_tool_dir):
127 self._logger.LogOutput(
128 '"{0}" and "{1}" are the same, sync skipped.'.format(
129 tool_dir, chrome_tool_dir))
130 return True
Han Shen91445322013-03-20 13:43:31 -0700131
Han Shen819f8622014-04-08 16:57:38 -0700132 # 2. Sync sources from user provided tool dir to chromiumos tool git.
133 local_tool_repo = repo_to_repo.FileRepo(tool_dir)
134 chrome_tool_repo = repo_to_repo.GitRepo(chrome_tool_dir, TEMP_BRANCH_NAME)
135 chrome_tool_repo._root_dir = chrome_tool_dir
Han Shen03d30982014-06-12 11:22:29 -0700136 # Delete all stuff except '.git' before start mapping.
137 self._ce.RunCommand(
138 'cd {0} && find . -maxdepth 1 -not -name ".git" -not -name "." '
139 r'\( -type f -exec rm {{}} \; -o '
140 r' -type d -exec rm -fr {{}} \; \)'.format(
141 chrome_tool_dir))
Han Shen819f8622014-04-08 16:57:38 -0700142 local_tool_repo.MapSources(chrome_tool_repo.GetRoot())
143
144 # 3. Ensure after sync tree is the same.
145 if self.IsTreeSame(tool_dir, chrome_tool_dir):
Han Shen91445322013-03-20 13:43:31 -0700146 self._logger.LogOutput('Sync successfully done.')
Han Shen819f8622014-04-08 16:57:38 -0700147 else:
148 self._logger.LogError('Sync not successful, aborted.')
149 return False
Han Shen91445322013-03-20 13:43:31 -0700150
151 # 4. Commit all changes.
Han Shen03d30982014-06-12 11:22:29 -0700152 # 4.1 Try to get some information about the tool dir we are using.
153 cmd = 'cd {0} && git log -1 --pretty=oneline'.format(tool_dir)
154 tool_dir_extra_info = None
Luis Lozano036c9232015-12-10 10:47:01 -0800155 ret, tool_dir_extra_info, _ = self._ce.RunCommandWOutput(
156 cmd, print_to_console=False)
Han Shen03d30982014-06-12 11:22:29 -0700157 commit_message = 'Synced with tool source tree at - "{0}".'.format(tool_dir)
158 if not ret:
159 commit_message += '\nGit log for {0}:\n{1}'.format(
160 tool_dir, tool_dir_extra_info)
161
162 if chrome_tool_repo.CommitLocally(commit_message):
Han Shen91445322013-03-20 13:43:31 -0700163 self._logger.LogError('Commit to local branch "{0}" failed, aborted.'.
Han Shen819f8622014-04-08 16:57:38 -0700164 format(TEMP_BRANCH_NAME))
Han Shen91445322013-03-20 13:43:31 -0700165 return False
166 return True
167
168 def CheckoutBranch(self):
Han Shen819f8622014-04-08 16:57:38 -0700169 """Checkout working branch for the tools.
Han Shen91445322013-03-20 13:43:31 -0700170
Han Shen819f8622014-04-08 16:57:38 -0700171 Returns:
172 True: if operation succeeds.
173 """
Han Shen91445322013-03-20 13:43:31 -0700174
Han Shen819f8622014-04-08 16:57:38 -0700175 if self._gcc_branch:
176 rv = self.CheckoutToolBranch('gcc', self._gcc_branch)
177 if rv:
178 self._gcc_branch_tree = rv
179 else:
180 return False
181
182 if self._binutils_branch:
183 rv = self.CheckoutToolBranch('binutils', self._binutils_branch)
184 if rv:
185 self._binutils_branch_tree = rv
186 else:
187 return False
188
Han Shen91445322013-03-20 13:43:31 -0700189 return True
190
Han Shen819f8622014-04-08 16:57:38 -0700191 def CheckoutToolBranch(self, tool_name, tool_branch):
192 """Checkout the tool branch for a certain tool.
193
194 Args:
195 tool_name: either 'gcc' or 'binutils'
196 tool_branch: tool branch to use
197 Returns:
198 True: if operation succeeds. Otherwise False.
Han Shen91445322013-03-20 13:43:31 -0700199 """
Han Shen819f8622014-04-08 16:57:38 -0700200
201 chrome_tool_dir = self.GetChromeOsToolDir(tool_name)
202 command = 'cd "{0}" && git checkout {1}'.format(
203 chrome_tool_dir, tool_branch)
204 if not self._ce.RunCommand(command, print_to_console=True):
205 # Get 'TREE' value of this commit
206 command = ('cd "{0}" && git cat-file -p {1} '
207 '| grep -E "^tree [a-f0-9]+$" '
208 '| cut -d" " -f2').format(chrome_tool_dir, tool_branch)
Luis Lozano036c9232015-12-10 10:47:01 -0800209 ret, stdout, _ = self._ce.RunCommandWOutput(
210 command, print_to_console=False)
Han Shen819f8622014-04-08 16:57:38 -0700211 # Pipe operation always has a zero return value. So need to check if
212 # stdout is valid.
213 if not ret and stdout and re.match(
214 '[0-9a-h]{40}', stdout.strip(), re.IGNORECASE):
215 tool_branch_tree = stdout.strip()
216 self._logger.LogOutput('Find tree for {0} branch "{1}" - "{2}"'.format(
217 tool_name, tool_branch, tool_branch_tree))
218 return tool_branch_tree
219 self._logger.LogError(('Failed to checkout "{0}" or failed to '
220 'get tree value, aborted.').format(tool_branch))
221 return None
222
223 def FindEbuildFile(self):
224 """Find the ebuild files for the tools.
225
226 Returns:
227 True: if operation succeeds.
228 """
229
230 if self._gcc_branch:
231 (rv, ef, efn) = self.FindToolEbuildFile('gcc')
232 if rv:
233 self._gcc_ebuild_file = ef
234 self._gcc_ebuild_file_name = efn
235 else:
236 return False
237
238 if self._binutils_branch:
239 (rv, ef, efn) = self.FindToolEbuildFile('binutils')
240 if rv:
241 self._binutils_ebuild_file = ef
242 self._binutils_ebuild_file_name = efn
243 else:
244 return False
245
246 return True
247
248 def FindToolEbuildFile(self, tool_name):
249 """Find ebuild file for a specific tool.
250
251 Args:
252 tool_name: either "gcc" or "binutils".
253 Returns:
254 A triplet that consisits of whether operation succeeds or not,
255 tool ebuild file full path and tool ebuild file name.
256 """
257
258 # To get the active gcc ebuild file, we need a workable chroot first.
259 if not os.path.exists(
260 os.path.join(self._chromeos_root, 'chroot')) and self._ce.RunCommand(
261 'cd "{0}" && cros_sdk --create'.format(self._chromeos_root)):
262 self._logger.LogError(('Failed to install a initial chroot, aborted.\n'
263 'If previous bootstrap failed, do a '
264 '"cros_sdk --delete" to remove '
265 'in-complete chroot.'))
266 return (False, None, None)
267
Luis Lozano036c9232015-12-10 10:47:01 -0800268 rv, stdout, _ = self._ce.ChrootRunCommandWOutput(
Han Shen819f8622014-04-08 16:57:38 -0700269 self._chromeos_root, 'equery w sys-devel/{0}'.format(tool_name),
Luis Lozano036c9232015-12-10 10:47:01 -0800270 print_to_console=True)
Han Shen819f8622014-04-08 16:57:38 -0700271 if rv:
272 self._logger.LogError(
273 ('Failed to execute inside chroot '
274 '"equery w sys-devel/{0}", aborted.').format(tool_name))
275 return (False, None, None)
276 m = re.match(r'^.*/({0}/(.*\.ebuild))$'.format(
277 EBUILD_PATH_PATTERN.format(tool_name)), stdout)
278 if not m:
279 self._logger.LogError(
280 ('Failed to find {0} ebuild file, aborted. '
281 'If previous bootstrap failed, do a "cros_sdk --delete" to remove '
282 'in-complete chroot.').format(tool_name))
283 return (False, None, None)
284 tool_ebuild_file = os.path.join(self._chromeos_root, m.group(1))
285 tool_ebuild_file_name = m.group(2)
286
287 return (True, tool_ebuild_file, tool_ebuild_file_name)
288
289 def InplaceModifyEbuildFile(self):
290 """Modify the ebuild file.
291
292 Returns:
293 True if operation succeeds.
294 """
295
296 # Note we shall not use remote branch name (eg. "cros/gcc.gnu.org/...") in
297 # CROS_WORKON_COMMIT, we have to use GITHASH. So we call GitGetCommitHash on
298 # tool_branch.
299 if self._gcc_branch:
300 tool_branch_githash = misc.GitGetCommitHash(
301 self.GetChromeOsToolDir('gcc'), self._gcc_branch)
302 if not tool_branch_githash:
303 return False
304 if not self.InplaceModifyToolEbuildFile(
305 tool_branch_githash, self._gcc_branch_tree, self._gcc_ebuild_file):
306 return False
307
308 if self._binutils_branch:
309 tool_branch_githash = misc.GitGetCommitHash(
310 self.GetChromeOsToolDir('binutils'), self._binutils_branch)
311 if not self.InplaceModifyToolEbuildFile(
312 tool_branch_githash, self._binutils_branch_tree,
313 self._binutils_ebuild_file):
314 return False
315 return True
316
317 @staticmethod
318 def ResetToolEbuildFile(chromeos_root, tool_name):
319 """Reset tool ebuild file to clean state.
320
321 Args:
322 chromeos_root: chromeos source tree
323 tool_name: either "gcc" or "binutils"
324 Returns:
325 True if operation succeds.
326 """
327 rv = misc.GetGitChangesAsList(
328 os.path.join(chromeos_root, CHROMIUMOS_OVERLAY_PATH),
329 path=('sys-devel/{0}/{0}-*.ebuild'.format(tool_name)),
330 staged=False)
331 if rv:
332 cmd = 'cd {0} && git checkout --'.format(os.path.join(
333 chromeos_root, CHROMIUMOS_OVERLAY_PATH))
334 for g in rv:
335 cmd += ' ' + g
336 rv = command_executer.GetCommandExecuter().RunCommand(cmd)
337 if rv:
338 logger.GetLogger().LogWarning(
339 'Failed to reset the ebuild file. Please refer to log above.')
340 return False
341 else:
342 logger.GetLogger().LogWarning(
343 'Note - did not find any modified {0} ebuild file.'.format(tool_name))
344 # Fall through
345 return True
346
347 def GetChromeOsToolDir(self, tool_name):
348 """Return the chromeos git dir for a specific tool.
349
350 Args:
351 tool_name: either 'gcc' or 'binutils'.
352 Returns:
353 Absolute git path for the tool.
354 """
355
356 return os.path.join(
357 self._chromeos_root, REPO_PATH_PATTERN.format(tool_name))
358
359 def InplaceModifyToolEbuildFile(
360 self, tool_branch_githash, tool_branch_tree, tool_ebuild_file):
361 """Using sed to fill properly values into the ebuild file.
362
363 Args:
364 tool_branch_githash: githash for tool_branch
365 tool_branch_tree: treeish for the tool branch
366 tool_ebuild_file: tool ebuild file
367 Returns:
368 True: if operation succeeded.
369 """
370
371 command = ('sed -i '
372 '-e \'/^CROS_WORKON_COMMIT=".*"/i'
373 ' # The following line is modified by script.\' '
374 '-e \'s!^CROS_WORKON_COMMIT=".*"$!CROS_WORKON_COMMIT="{0}"!\' '
375 '-e \'/^CROS_WORKON_TREE=".*"/i'
376 ' # The following line is modified by script.\' '
377 '-e \'s!^CROS_WORKON_TREE=".*"$!CROS_WORKON_TREE="{1}"!\' '
378 '{2}').format(tool_branch_githash,
379 tool_branch_tree,
380 tool_ebuild_file)
Han Shen91445322013-03-20 13:43:31 -0700381 rv = self._ce.RunCommand(command)
382 if rv:
383 self._logger.LogError(
Han Shen819f8622014-04-08 16:57:38 -0700384 'Failed to modify commit and tree value for "{0}"", aborted.'.format(
385 tool_ebuild_file))
386 return False
387
388 # Warn that the ebuild file has been modified.
389 self._logger.LogWarning(
390 ('Ebuild file "{0}" is modified, to revert the file - \n'
391 'bootstrap_compiler.py --chromeos_root={1} '
392 '--reset_tool_ebuild_file').format(
393 tool_ebuild_file, self._chromeos_root))
394 return True
395
396 def DoBuildForBoard(self):
397 """Build tool for a specific board.
398
399 Returns:
400 True if operation succeeds.
401 """
402
403 if self._gcc_branch:
404 if not self.DoBuildToolForBoard('gcc'):
405 return False
406 if self._binutils_branch:
407 if not self.DoBuildToolForBoard('binutils'):
408 return False
409 return True
410
411 def DoBuildToolForBoard(self, tool_name):
412 """Build a specific tool for a specific board.
413
414 Args:
415 tool_name: either "gcc" or "binutils"
416 Returns:
417 True if operation succeeds.
418 """
419
Han Shenfe3001c2014-04-28 16:36:28 -0700420 boards_to_build = self._board.split(',')
Han Shen819f8622014-04-08 16:57:38 -0700421
Han Shenfe3001c2014-04-28 16:36:28 -0700422 failed = []
423 for board in boards_to_build:
424 if board == 'host':
425 command = 'sudo emerge sys-devel/{0}'.format(tool_name)
426 else:
427 target = misc.GetCtargetFromBoard(board, self._chromeos_root)
428 if not target:
429 self._logger.LogError(
430 'Unsupported board "{0}", skip.'.format(board))
431 failed.append(board)
432 continue
433 command = 'sudo emerge cross-{0}/{1}'.format(target, tool_name)
434
435 rv = self._ce.ChrootRunCommand(self._chromeos_root, command,
Luis Lozano036c9232015-12-10 10:47:01 -0800436 print_to_console=True)
Han Shenfe3001c2014-04-28 16:36:28 -0700437 if rv:
438 self._logger.LogError(
Han Shen03d30982014-06-12 11:22:29 -0700439 'Build {0} failed for {1}, aborted.'.format(tool_name, board))
Han Shenfe3001c2014-04-28 16:36:28 -0700440 failed.append(board)
441 else:
442 self._logger.LogOutput(
Han Shen03d30982014-06-12 11:22:29 -0700443 'Successfully built {0} for board {1}.'.format(tool_name, board))
Han Shenfe3001c2014-04-28 16:36:28 -0700444
Han Shen8dfdabd2014-05-08 10:15:09 -0700445 if failed:
Han Shen819f8622014-04-08 16:57:38 -0700446 self._logger.LogError(
Han Shenfe3001c2014-04-28 16:36:28 -0700447 'Failed to build {0} for the following board(s): "{1}"'.format(
448 tool_name, ' '.join(failed)))
Han Shen91445322013-03-20 13:43:31 -0700449 return False
Han Shenfe3001c2014-04-28 16:36:28 -0700450 # All boards build successfully
Han Shen91445322013-03-20 13:43:31 -0700451 return True
452
453 def DoBootstrapping(self):
Han Shen819f8622014-04-08 16:57:38 -0700454 """Do bootstrapping the chroot.
455
Han Shen03d30982014-06-12 11:22:29 -0700456 This step firstly downloads a prestine sdk, then use this sdk to build the
457 new sdk, finally use the new sdk to build every host package.
458
Han Shen819f8622014-04-08 16:57:38 -0700459 Returns:
460 True if operation succeeds.
461 """
462
Han Shen91445322013-03-20 13:43:31 -0700463 logfile = os.path.join(self._chromeos_root, 'bootstrap.log')
Han Shen819f8622014-04-08 16:57:38 -0700464 command = 'cd "{0}" && cros_sdk --delete --bootstrap |& tee "{1}"'.format(
465 self._chromeos_root, logfile)
Luis Lozano036c9232015-12-10 10:47:01 -0800466 rv = self._ce.RunCommand(command, print_to_console=True)
Han Shen91445322013-03-20 13:43:31 -0700467 if rv:
468 self._logger.LogError('Bootstrapping failed, log file - "{0}"\n'.format(
469 logfile))
470 return False
471
472 self._logger.LogOutput('Bootstrap succeeded.')
473 return True
474
Han Shen03d30982014-06-12 11:22:29 -0700475 def BuildAndInstallAmd64Host(self):
476 """Build amd64-host (host) packages.
477
478 Build all host packages in the newly-bootstrapped 'chroot' using *NEW*
479 toolchain.
480
481 So actually we perform 2 builds of all host packages -
482 1. build new toolchain using old toolchain and build all host packages
483 using the newly built toolchain
484 2. build the new toolchain again but using new toolchain built in step 1,
485 and build all host packages using the newly built toolchain
486
487 Returns:
488 True if operation succeeds.
489 """
490
491 cmd = ('cd {0} && cros_sdk -- -- ./setup_board --board=amd64-host '
492 '--accept_licenses=@CHROMEOS --skip_chroot_upgrade --nousepkg '
493 '--reuse_pkgs_from_local_boards').format(self._chromeos_root)
Luis Lozano036c9232015-12-10 10:47:01 -0800494 rv = self._ce.RunCommand(cmd, print_to_console=True)
Han Shen03d30982014-06-12 11:22:29 -0700495 if rv:
496 self._logger.LogError('Build amd64-host failed.')
497 return False
498
499 # Package amd64-host into 'built-sdk.tar.xz'.
500 sdk_package = os.path.join(self._chromeos_root, 'built-sdk.tar.xz')
501 cmd = ('cd {0}/chroot/build/amd64-host && sudo XZ_OPT="-e9" '
502 'tar --exclude="usr/lib/debug/*" --exclude="packages/*" '
503 '--exclude="tmp/*" --exclude="usr/local/build/autotest/*" '
504 '--sparse -I xz -vcf {1} . && sudo chmod a+r {1}').format(
505 self._chromeos_root, sdk_package)
Luis Lozano036c9232015-12-10 10:47:01 -0800506 rv = self._ce.RunCommand(cmd, print_to_console=True)
Han Shen03d30982014-06-12 11:22:29 -0700507 if rv:
508 self._logger.LogError('Failed to create "built-sdk.tar.xz".')
509 return False
510
511 # Install amd64-host into a new chroot.
512 cmd = ('cd {0} && cros_sdk --chroot new-sdk-chroot --download --replace '
513 '--nousepkg --url file://{1}').format(
514 self._chromeos_root, sdk_package)
Luis Lozano036c9232015-12-10 10:47:01 -0800515 rv = self._ce.RunCommand(cmd, print_to_console=True)
Han Shen03d30982014-06-12 11:22:29 -0700516 if rv:
517 self._logger.LogError('Failed to install "built-sdk.tar.xz".')
518 return False
519 self._logger.LogOutput(
520 'Successfully installed built-sdk.tar.xz into a new chroot.\nAll done.')
521
522 # Rename the newly created new-sdk-chroot to chroot.
523 cmd = ('cd {0} && sudo mv chroot chroot-old && '
524 'sudo mv new-sdk-chroot chroot').format(self._chromeos_root)
Luis Lozano036c9232015-12-10 10:47:01 -0800525 rv = self._ce.RunCommand(cmd, print_to_console=True)
Han Shen03d30982014-06-12 11:22:29 -0700526 return rv == 0
527
Han Shen91445322013-03-20 13:43:31 -0700528 def Do(self):
Han Shen819f8622014-04-08 16:57:38 -0700529 """Entrance of the class.
530
531 Returns:
532 True if everything is ok.
533 """
534
535 if (self.SubmitToLocalBranch() and
536 self.CheckoutBranch() and
537 self.FindEbuildFile() and
538 self.InplaceModifyEbuildFile()):
539 if self._setup_tool_ebuild_file_only:
540 # Everything is done, we are good.
541 ret = True
542 else:
543 if self._board:
544 ret = self.DoBuildForBoard()
545 else:
546 # This implies '--bootstrap'.
Han Shen03d30982014-06-12 11:22:29 -0700547 ret = (self.DoBootstrapping() and
548 (self._disable_2nd_bootstrap or
549 self.BuildAndInstallAmd64Host()))
Han Shen91445322013-03-20 13:43:31 -0700550 else:
551 ret = False
Han Shen91445322013-03-20 13:43:31 -0700552 return ret
553
554
555def Main(argv):
556 parser = optparse.OptionParser()
557 parser.add_option('-c', '--chromeos_root', dest='chromeos_root',
Han Shen819f8622014-04-08 16:57:38 -0700558 help=('Optional. ChromeOs root dir. '
559 'When not specified, chromeos root will be deduced '
560 'from current working directory.'))
561 parser.add_option('--gcc_branch', dest='gcc_branch',
Han Shen91445322013-03-20 13:43:31 -0700562 help=('The branch to test against. '
563 'This branch must be a local branch '
564 'inside "src/third_party/gcc". '
Han Shen819f8622014-04-08 16:57:38 -0700565 'Notice, this must not be used with "--gcc_dir".'))
566 parser.add_option('--binutils_branch', dest='binutils_branch',
567 help=('The branch to test against binutils. '
568 'This branch must be a local branch '
569 'inside "src/third_party/binutils". '
570 'Notice, this must not be used with '
571 '"--binutils_dir".'))
Han Shen91445322013-03-20 13:43:31 -0700572 parser.add_option('-g', '--gcc_dir', dest='gcc_dir',
573 help=('Use a local gcc tree to do bootstrapping. '
Han Shen819f8622014-04-08 16:57:38 -0700574 'Notice, this must not be used with "--gcc_branch".'))
575 parser.add_option('--binutils_dir', dest='binutils_dir',
576 help=('Use a local binutils tree to do bootstrapping. '
577 'Notice, this must not be used with '
578 '"--binutils_branch".'))
Han Shen91445322013-03-20 13:43:31 -0700579 parser.add_option('--fixperm', dest='fixperm',
580 default=False, action='store_true',
581 help=('Fix the (notorious) permission error '
582 'while trying to bootstrap the chroot. '
583 'Note this takes an extra 10-15 minutes '
584 'and is only needed once per chromiumos tree.'))
Han Shen819f8622014-04-08 16:57:38 -0700585 parser.add_option('--setup_tool_ebuild_file_only',
586 dest='setup_tool_ebuild_file_only',
Han Shen91445322013-03-20 13:43:31 -0700587 default=False, action='store_true',
Han Shen819f8622014-04-08 16:57:38 -0700588 help=('Setup gcc and/or binutils ebuild file '
589 'to pick up the branch (--gcc/binutils_branch) or '
590 'use gcc and/or binutils source (--gcc/binutils_dir) '
591 'and exit. Keep chroot as is. This should not be '
592 'used with --gcc/binutils_dir/branch options.'))
593 parser.add_option('--reset_tool_ebuild_file', dest='reset_tool_ebuild_file',
Han Shen91445322013-03-20 13:43:31 -0700594 default=False, action='store_true',
595 help=('Reset the modification that is done by this script.'
596 'Note, when this script is running, it will modify '
Han Shen819f8622014-04-08 16:57:38 -0700597 'the active gcc/binutils ebuild file. Use this '
598 'option to reset (what this script has done) '
599 'and exit. This should not be used with -- '
600 'gcc/binutils_dir/branch options.'))
601 parser.add_option('--board', dest='board', default=None,
Han Shenfe3001c2014-04-28 16:36:28 -0700602 help=('Only build toolchain for specific board(s). '
Han Shen819f8622014-04-08 16:57:38 -0700603 'Use "host" to build for host. '
Han Shenfe3001c2014-04-28 16:36:28 -0700604 'Use "," to seperate multiple boards. '
Han Shen819f8622014-04-08 16:57:38 -0700605 'This does not perform a chroot bootstrap.'))
606 parser.add_option('--bootstrap', dest='bootstrap',
607 default=False, action='store_true',
608 help=('Performs a chroot bootstrap. '
609 'Note, this will *destroy* your current chroot.'))
Han Shen03d30982014-06-12 11:22:29 -0700610 parser.add_option('--disable-2nd-bootstrap', dest='disable_2nd_bootstrap',
611 default=False, action='store_true',
612 help=('Disable a second bootstrap '
613 '(build of amd64-host stage).'))
Han Shen819f8622014-04-08 16:57:38 -0700614
Han Shen91445322013-03-20 13:43:31 -0700615 options = parser.parse_args(argv)[0]
Han Shen819f8622014-04-08 16:57:38 -0700616 # Trying to deduce chromeos root from current directory.
Han Shen91445322013-03-20 13:43:31 -0700617 if not options.chromeos_root:
Han Shen819f8622014-04-08 16:57:38 -0700618 logger.GetLogger().LogOutput('Trying to deduce chromeos root ...')
619 wdir = os.getcwd()
620 while wdir and wdir != '/':
621 if misc.IsChromeOsTree(wdir):
622 logger.GetLogger().LogOutput('Find chromeos_root: {}'.format(wdir))
623 options.chromeos_root = wdir
624 break
625 wdir = os.path.dirname(wdir)
626
627 if not options.chromeos_root:
628 parser.error('Missing or failing to deduce mandatory option "--chromeos".')
Han Shen91445322013-03-20 13:43:31 -0700629 return 1
630
631 options.chromeos_root = os.path.abspath(
Han Shen819f8622014-04-08 16:57:38 -0700632 os.path.expanduser(options.chromeos_root))
Han Shen91445322013-03-20 13:43:31 -0700633
634 if not os.path.isdir(options.chromeos_root):
635 logger.GetLogger().LogError(
Han Shen819f8622014-04-08 16:57:38 -0700636 '"{0}" does not exist.'.format(options.chromeos_root))
Han Shen91445322013-03-20 13:43:31 -0700637 return 1
638
639 if options.fixperm:
640 # Fix perm error before continuing.
Han Shen819f8622014-04-08 16:57:38 -0700641 cmd = (r'sudo find "{0}" \( -name ".cache" -type d -prune \) -o '
642 r'\( -name "chroot" -type d -prune \) -o '
643 r'\( -type f -exec chmod a+r {{}} \; \) -o '
644 r'\( -type d -exec chmod a+rx {{}} \; \)').format(
645 options.chromeos_root)
Han Shen91445322013-03-20 13:43:31 -0700646 logger.GetLogger().LogOutput(
Han Shen819f8622014-04-08 16:57:38 -0700647 'Fixing perm issues for chromeos root, this might take some time.')
Han Shen91445322013-03-20 13:43:31 -0700648 command_executer.GetCommandExecuter().RunCommand(cmd)
649
Han Shen819f8622014-04-08 16:57:38 -0700650 if options.reset_tool_ebuild_file:
651 if (options.gcc_dir or options.gcc_branch or
652 options.binutils_dir or options.binutils_branch):
Han Shen91445322013-03-20 13:43:31 -0700653 logger.GetLogger().LogWarning(
Han Shen819f8622014-04-08 16:57:38 -0700654 'Ignoring any "--gcc/binutils_dir" and/or "--gcc/binutils_branch".')
655 if options.setup_tool_ebuild_file_only:
656 logger.GetLogger().LogError(
657 ('Conflict options "--reset_tool_ebuild_file" '
658 'and "--setup_tool_ebuild_file_only".'))
Han Shen91445322013-03-20 13:43:31 -0700659 return 1
Han Shen819f8622014-04-08 16:57:38 -0700660 rv = Bootstrapper.ResetToolEbuildFile(options.chromeos_root, 'gcc')
661 rv1 = Bootstrapper.ResetToolEbuildFile(options.chromeos_root, 'binutils')
662 return 0 if (rv and rv1) else 1
Han Shen91445322013-03-20 13:43:31 -0700663
664 if options.gcc_dir:
665 options.gcc_dir = os.path.abspath(os.path.expanduser(options.gcc_dir))
666 if not os.path.isdir(options.gcc_dir):
667 logger.GetLogger().LogError(
Han Shen819f8622014-04-08 16:57:38 -0700668 '"{0}" does not exist.'.format(options.gcc_dir))
Han Shen91445322013-03-20 13:43:31 -0700669 return 1
670
Han Shen819f8622014-04-08 16:57:38 -0700671 if options.gcc_branch and options.gcc_dir:
672 parser.error('Only one of "--gcc_dir" and "--gcc_branch" can be specified.')
Han Shen91445322013-03-20 13:43:31 -0700673 return 1
Han Shen819f8622014-04-08 16:57:38 -0700674
675 if options.binutils_dir:
676 options.binutils_dir = os.path.abspath(
677 os.path.expanduser(options.binutils_dir))
678 if not os.path.isdir(options.binutils_dir):
679 logger.GetLogger().LogError(
680 '"{0}" does not exist.'.format(options.binutils_dir))
681 return 1
682
683 if options.binutils_branch and options.binutils_dir:
684 parser.error('Only one of "--binutils_dir" and '
685 '"--binutils_branch" can be specified.')
686 return 1
687
688 if (not (options.binutils_branch or options.binutils_dir or
689 options.gcc_branch or options.gcc_dir)):
690 parser.error(('At least one of "--gcc_dir", "--gcc_branch", '
691 '"--binutils_dir" and "--binutils_branch" must '
692 'be specified.'))
693 return 1
694
695 if not options.board and not options.bootstrap:
696 parser.error('You must specify either "--board" or "--bootstrap".')
697 return 1
698
Han Shen03d30982014-06-12 11:22:29 -0700699 if (options.board and options.bootstrap and
700 not options.setup_tool_ebuild_file_only):
Han Shen819f8622014-04-08 16:57:38 -0700701 parser.error('You must specify only one of "--board" and "--bootstrap".')
Han Shen91445322013-03-20 13:43:31 -0700702 return 1
703
Han Shen03d30982014-06-12 11:22:29 -0700704 if not options.bootstrap and options.disable_2nd_bootstrap:
705 parser.error('"--disable-2nd-bootstrap" has no effect '
706 'without specifying "--bootstrap".')
707 return 1
708
Han Shen91445322013-03-20 13:43:31 -0700709 if Bootstrapper(
Han Shen819f8622014-04-08 16:57:38 -0700710 options.chromeos_root,
711 gcc_branch=options.gcc_branch, gcc_dir=options.gcc_dir,
712 binutils_branch=options.binutils_branch,
713 binutils_dir=options.binutils_dir,
714 board=options.board,
Han Shen03d30982014-06-12 11:22:29 -0700715 disable_2nd_bootstrap=options.disable_2nd_bootstrap,
Han Shen819f8622014-04-08 16:57:38 -0700716 setup_tool_ebuild_file_only=options.setup_tool_ebuild_file_only).Do():
Han Shen91445322013-03-20 13:43:31 -0700717 return 0
718 return 1
719
720
721if __name__ == '__main__':
722 retval = Main(sys.argv)
723 sys.exit(retval)