blob: 2df1639d65fcf25e5ac81cec81dc28d48429c350 [file] [log] [blame]
shenhan8e8b0c22013-02-19 22:34:16 +00001#!/usr/bin/python
bjanakiraman7f4a4852013-02-15 04:35:28 +00002#
Rahul Chaudhry8ac4ec02014-11-01 09:31:15 -07003# Copyright 2010 The Chromium OS Authors. All rights reserved.
4# Use of this source code is governed by a BSD-style license that can be
5# found in the LICENSE file.
bjanakiraman7f4a4852013-02-15 04:35:28 +00006"""Script to build the ChromeOS toolchain.
7
8This script sets up the toolchain if you give it the gcctools directory.
9"""
10
Luis Lozanof2a3ef42015-12-15 13:49:30 -080011__author__ = 'asharif@google.com (Ahmad Sharif)'
bjanakiraman7f4a4852013-02-15 04:35:28 +000012
asharif80c6e552013-02-15 04:35:40 +000013import getpass
bjanakiraman7f4a4852013-02-15 04:35:28 +000014import optparse
asharif17621302013-02-15 04:46:35 +000015import os
bjanakiraman7f4a4852013-02-15 04:35:28 +000016import sys
asharifc97199a2013-02-15 22:48:45 +000017import tempfile
kbaclawski20082a02013-02-16 02:12:57 +000018
asharif252df0f2013-02-15 04:46:28 +000019import tc_enter_chroot
raymes01959ae2013-02-15 04:50:07 +000020from utils import command_executer
shenhanad803432013-02-16 03:14:51 +000021from utils import constants
kbaclawski20082a02013-02-16 02:12:57 +000022from utils import misc
bjanakiraman7f4a4852013-02-15 04:35:28 +000023
asharif5a9bb462013-02-15 04:50:57 +000024
asharifc97199a2013-02-15 22:48:45 +000025class ToolchainPart(object):
Luis Lozanof2a3ef42015-12-15 13:49:30 -080026
27 def __init__(self,
28 name,
29 source_path,
30 chromeos_root,
31 board,
32 incremental,
33 build_env,
34 gcc_enable_ccache=False):
asharifc97199a2013-02-15 22:48:45 +000035 self._name = name
kbaclawski20082a02013-02-16 02:12:57 +000036 self._source_path = misc.CanonicalizePath(source_path)
asharifc97199a2013-02-15 22:48:45 +000037 self._chromeos_root = chromeos_root
38 self._board = board
Luis Lozanof2a3ef42015-12-15 13:49:30 -080039 self._ctarget = misc.GetCtargetFromBoard(self._board, self._chromeos_root)
Rahul Chaudhry215c12f2014-11-04 15:18:47 -080040 self._gcc_libs_dest = misc.GetGccLibsDestForBoard(self._board,
Luis Lozanof2a3ef42015-12-15 13:49:30 -080041 self._chromeos_root)
42 self.tag = '%s-%s' % (name, self._ctarget)
asharifc97199a2013-02-15 22:48:45 +000043 self._ce = command_executer.GetCommandExecuter()
Luis Lozanof2a3ef42015-12-15 13:49:30 -080044 self._mask_file = os.path.join(self._chromeos_root, 'chroot',
45 'etc/portage/package.mask/cross-%s' %
46 self._ctarget)
asharifc97199a2013-02-15 22:48:45 +000047 self._new_mask_file = None
48
Han Shene4b6f222013-11-22 10:02:38 -080049 self._chroot_source_path = os.path.join(constants.MOUNTED_TOOLCHAIN_ROOT,
Luis Lozanof2a3ef42015-12-15 13:49:30 -080050 self._name).lstrip('/')
asharifc97199a2013-02-15 22:48:45 +000051 self._incremental = incremental
52 self._build_env = build_env
llozanof2726d22013-03-09 01:29:37 +000053 self._gcc_enable_ccache = gcc_enable_ccache
asharifc97199a2013-02-15 22:48:45 +000054
55 def RunSetupBoardIfNecessary(self):
Luis Lozanof2a3ef42015-12-15 13:49:30 -080056 cross_symlink = os.path.join(self._chromeos_root, 'chroot',
57 'usr/local/bin/emerge-%s' % self._board)
asharifc97199a2013-02-15 22:48:45 +000058 if not os.path.exists(cross_symlink):
Luis Lozanof2a3ef42015-12-15 13:49:30 -080059 command = ('%s/setup_board --board=%s' %
Rahul Chaudhry8ac4ec02014-11-01 09:31:15 -070060 (misc.CHROMEOS_SCRIPTS_DIR, self._board))
asharifca3c6c12013-02-15 23:17:54 +000061 self._ce.ChrootRunCommand(self._chromeos_root, command)
asharifc97199a2013-02-15 22:48:45 +000062
63 def Build(self):
shenhanbecf6242013-02-19 20:43:32 +000064 rv = 1
asharifc97199a2013-02-15 22:48:45 +000065 try:
asharif7dd6d862013-02-15 23:17:46 +000066 self.UninstallTool()
asharifc97199a2013-02-15 22:48:45 +000067 self.MoveMaskFile()
cmtice80d257f2013-02-15 23:44:51 +000068 self.MountSources(False)
asharif9e3cf6e2013-02-16 03:13:38 +000069 self.RemoveCompiledFile()
shenhanbecf6242013-02-19 20:43:32 +000070 rv = self.BuildTool()
asharifc97199a2013-02-15 22:48:45 +000071 finally:
72 self.UnMoveMaskFile()
llozano9b84cb62013-03-11 21:08:31 +000073 return rv
asharifc97199a2013-02-15 22:48:45 +000074
75 def RemoveCompiledFile(self):
Luis Lozanof2a3ef42015-12-15 13:49:30 -080076 compiled_file = os.path.join(self._chromeos_root, 'chroot',
77 'var/tmp/portage/cross-%s' % self._ctarget,
78 '%s-9999' % self._name, '.compiled')
79 command = 'rm -f %s' % compiled_file
asharifc97199a2013-02-15 22:48:45 +000080 self._ce.RunCommand(command)
81
cmtice80d257f2013-02-15 23:44:51 +000082 def MountSources(self, unmount_source):
asharifc97199a2013-02-15 22:48:45 +000083 mount_points = []
Luis Lozanof2a3ef42015-12-15 13:49:30 -080084 mounted_source_path = os.path.join(self._chromeos_root, 'chroot',
asharifc97199a2013-02-15 22:48:45 +000085 self._chroot_source_path)
Luis Lozanof2a3ef42015-12-15 13:49:30 -080086 src_mp = tc_enter_chroot.MountPoint(self._source_path, mounted_source_path,
87 getpass.getuser(), 'ro')
asharifc97199a2013-02-15 22:48:45 +000088 mount_points.append(src_mp)
89
Luis Lozanof2a3ef42015-12-15 13:49:30 -080090 build_suffix = 'build-%s' % self._ctarget
91 build_dir = '%s-%s' % (self._source_path, build_suffix)
asharifc97199a2013-02-15 22:48:45 +000092
93 if not self._incremental and os.path.exists(build_dir):
Luis Lozanof2a3ef42015-12-15 13:49:30 -080094 command = 'rm -rf %s/*' % build_dir
asharifc97199a2013-02-15 22:48:45 +000095 self._ce.RunCommand(command)
96
97 # Create a -build directory for the objects.
Luis Lozanof2a3ef42015-12-15 13:49:30 -080098 command = 'mkdir -p %s' % build_dir
asharifc97199a2013-02-15 22:48:45 +000099 self._ce.RunCommand(command)
100
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800101 mounted_build_dir = os.path.join(self._chromeos_root, 'chroot', '%s-%s' %
102 (self._chroot_source_path, build_suffix))
103 build_mp = tc_enter_chroot.MountPoint(build_dir, mounted_build_dir,
104 getpass.getuser())
asharifc97199a2013-02-15 22:48:45 +0000105 mount_points.append(build_mp)
106
cmtice80d257f2013-02-15 23:44:51 +0000107 if unmount_source:
108 unmount_statuses = [mp.UnMount() == 0 for mp in mount_points]
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800109 assert all(unmount_statuses), 'Could not unmount all mount points!'
cmtice80d257f2013-02-15 23:44:51 +0000110 else:
111 mount_statuses = [mp.DoMount() == 0 for mp in mount_points]
112
113 if not all(mount_statuses):
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800114 mounted = [mp
115 for mp, status in zip(mount_points, mount_statuses)
116 if status]
cmtice80d257f2013-02-15 23:44:51 +0000117 unmount_statuses = [mp.UnMount() == 0 for mp in mounted]
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800118 assert all(unmount_statuses), 'Could not unmount all mount points!'
asharifc97199a2013-02-15 22:48:45 +0000119
asharif7dd6d862013-02-15 23:17:46 +0000120 def UninstallTool(self):
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800121 command = 'sudo CLEAN_DELAY=0 emerge -C cross-%s/%s' % (self._ctarget,
122 self._name)
asharifca3c6c12013-02-15 23:17:54 +0000123 self._ce.ChrootRunCommand(self._chromeos_root, command)
asharif7dd6d862013-02-15 23:17:46 +0000124
asharifc97199a2013-02-15 22:48:45 +0000125 def BuildTool(self):
126 env = self._build_env
asharif9e499162013-02-16 02:41:39 +0000127 # FEATURES=buildpkg adds minutes of time so we disable it.
shenhanfdc0f572013-02-19 18:48:36 +0000128 # TODO(shenhan): keep '-sandbox' for a while for compatibility, then remove
129 # it after a while.
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800130 features = ('nostrip userpriv userfetch -usersandbox -sandbox noclean '
131 '-buildpkg')
132 env['FEATURES'] = features
asharifc97199a2013-02-15 22:48:45 +0000133
134 if self._incremental:
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800135 env['FEATURES'] += ' keepwork'
asharifc97199a2013-02-15 22:48:45 +0000136
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800137 if 'USE' in env:
138 env['USE'] += ' multislot mounted_%s' % self._name
cmticecbc868a2013-02-21 22:52:46 +0000139 else:
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800140 env['USE'] = 'multislot mounted_%s' % self._name
cmticecbc868a2013-02-21 22:52:46 +0000141
llozanof2726d22013-03-09 01:29:37 +0000142 # Disable ccache in our compilers. cache may be problematic for us.
143 # It ignores compiler environments settings and it is not clear if
144 # the cache hit algorithm verifies all the compiler binaries or
145 # just the driver.
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800146 if self._name == 'gcc' and not self._gcc_enable_ccache:
147 env['USE'] += ' -wrapper_ccache'
llozanof2726d22013-03-09 01:29:37 +0000148
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800149 env['%s_SOURCE_PATH' % self._name.upper()] = (
150 os.path.join('/', self._chroot_source_path))
151 env['ACCEPT_KEYWORDS'] = '~*'
152 env_string = ' '.join(["%s=\"%s\"" % var for var in env.items()])
153 command = 'emerge =cross-%s/%s-9999' % (self._ctarget, self._name)
154 full_command = 'sudo %s %s' % (env_string, command)
Luis Lozano4cea9de2013-03-20 12:32:56 -0700155 rv = self._ce.ChrootRunCommand(self._chromeos_root, full_command)
156 if rv != 0:
157 return rv
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800158 if self._name == 'gcc':
159 command = ('sudo cp -r /usr/lib/gcc/%s %s' %
Rahul Chaudhry215c12f2014-11-04 15:18:47 -0800160 (self._ctarget, self._gcc_libs_dest))
Luis Lozano4cea9de2013-03-20 12:32:56 -0700161 rv = self._ce.ChrootRunCommand(self._chromeos_root, command)
162 return rv
asharifc97199a2013-02-15 22:48:45 +0000163
asharifc97199a2013-02-15 22:48:45 +0000164 def MoveMaskFile(self):
165 self._new_mask_file = None
166 if os.path.isfile(self._mask_file):
167 self._new_mask_file = tempfile.mktemp()
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800168 command = 'sudo mv %s %s' % (self._mask_file, self._new_mask_file)
asharifc97199a2013-02-15 22:48:45 +0000169 self._ce.RunCommand(command)
170
171 def UnMoveMaskFile(self):
172 if self._new_mask_file:
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800173 command = 'sudo mv %s %s' % (self._new_mask_file, self._mask_file)
asharifc97199a2013-02-15 22:48:45 +0000174 self._ce.RunCommand(command)
bjanakiraman7f4a4852013-02-15 04:35:28 +0000175
bjanakiraman7f4a4852013-02-15 04:35:28 +0000176
asharif0d3535a2013-02-15 04:50:33 +0000177def Main(argv):
asharif19c73dd2013-02-15 04:35:37 +0000178 """The main function."""
asharif5a9bb462013-02-15 04:50:57 +0000179 # Common initializations
asharif19c73dd2013-02-15 04:35:37 +0000180 parser = optparse.OptionParser()
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800181 parser.add_option('-c',
182 '--chromeos_root',
183 dest='chromeos_root',
184 default='../../',
185 help=('ChromeOS root checkout directory'
186 ' uses ../.. if none given.'))
187 parser.add_option('-g',
188 '--gcc_dir',
189 dest='gcc_dir',
190 help='The directory where gcc resides.')
191 parser.add_option('--binutils_dir',
192 dest='binutils_dir',
193 help='The directory where binutils resides.')
194 parser.add_option('-x',
195 '--gdb_dir',
196 dest='gdb_dir',
197 help='The directory where gdb resides.')
198 parser.add_option('-b',
199 '--board',
200 dest='board',
201 default='x86-agz',
202 help='The target board.')
203 parser.add_option('-n',
204 '--noincremental',
205 dest='noincremental',
asharifc97199a2013-02-15 22:48:45 +0000206 default=False,
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800207 action='store_true',
208 help='Use FEATURES=keepwork to do incremental builds.')
209 parser.add_option('--cflags',
210 dest='cflags',
211 default='',
212 help='Build a compiler with specified CFLAGS')
213 parser.add_option('--cxxflags',
214 dest='cxxflags',
215 default='',
216 help='Build a compiler with specified CXXFLAGS')
217 parser.add_option('--cflags_for_target',
218 dest='cflags_for_target',
219 default='',
220 help='Build the target libraries with specified flags')
221 parser.add_option('--cxxflags_for_target',
222 dest='cxxflags_for_target',
223 default='',
224 help='Build the target libraries with specified flags')
225 parser.add_option('--ldflags',
226 dest='ldflags',
227 default='',
228 help='Build a compiler with specified LDFLAGS')
229 parser.add_option('-d',
230 '--debug',
231 dest='debug',
asharifc97199a2013-02-15 22:48:45 +0000232 default=False,
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800233 action='store_true',
234 help='Build a compiler with -g3 -O0 appended to both'
235 ' CFLAGS and CXXFLAGS.')
236 parser.add_option('-m',
237 '--mount_only',
238 dest='mount_only',
asharif86968c42013-02-15 23:44:37 +0000239 default=False,
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800240 action='store_true',
241 help='Just mount the tool directories.')
242 parser.add_option('-u',
243 '--unmount_only',
244 dest='unmount_only',
cmtice80d257f2013-02-15 23:44:51 +0000245 default=False,
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800246 action='store_true',
247 help='Just unmount the tool directories.')
248 parser.add_option('--extra_use_flags',
249 dest='extra_use_flags',
250 default='',
251 help='Extra flag for USE, to be passed to the ebuild. '
cmticecbc868a2013-02-21 22:52:46 +0000252 "('multislot' and 'mounted_<tool>' are always passed.)")
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800253 parser.add_option('--gcc_enable_ccache',
254 dest='gcc_enable_ccache',
llozanof2726d22013-03-09 01:29:37 +0000255 default=False,
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800256 action='store_true',
257 help='Enable ccache for the gcc invocations')
bjanakiraman7f4a4852013-02-15 04:35:28 +0000258
asharifc97199a2013-02-15 22:48:45 +0000259 options, _ = parser.parse_args(argv)
asharif17621302013-02-15 04:46:35 +0000260
kbaclawski20082a02013-02-16 02:12:57 +0000261 chromeos_root = misc.CanonicalizePath(options.chromeos_root)
cmtice80d257f2013-02-15 23:44:51 +0000262 if options.gcc_dir:
kbaclawski20082a02013-02-16 02:12:57 +0000263 gcc_dir = misc.CanonicalizePath(options.gcc_dir)
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800264 assert gcc_dir and os.path.isdir(gcc_dir), 'gcc_dir does not exist!'
shenhan8e8b0c22013-02-19 22:34:16 +0000265 if options.binutils_dir:
266 binutils_dir = misc.CanonicalizePath(options.binutils_dir)
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800267 assert os.path.isdir(binutils_dir), 'binutils_dir does not exist!'
cmtice80d257f2013-02-15 23:44:51 +0000268 if options.gdb_dir:
kbaclawski20082a02013-02-16 02:12:57 +0000269 gdb_dir = misc.CanonicalizePath(options.gdb_dir)
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800270 assert os.path.isdir(gdb_dir), 'gdb_dir does not exist!'
cmtice80d257f2013-02-15 23:44:51 +0000271 if options.unmount_only:
272 options.mount_only = False
273 elif options.mount_only:
274 options.unmount_only = False
asharifc97199a2013-02-15 22:48:45 +0000275 build_env = {}
cmticee59ac272013-02-19 20:20:09 +0000276 if options.cflags:
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800277 build_env['CFLAGS'] = '`portageq envvar CFLAGS` ' + options.cflags
cmticee59ac272013-02-19 20:20:09 +0000278 if options.cxxflags:
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800279 build_env['CXXFLAGS'] = '`portageq envvar CXXFLAGS` ' + options.cxxflags
carrot2b549ca2013-02-19 22:45:25 +0000280 if options.cflags_for_target:
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800281 build_env['CFLAGS_FOR_TARGET'] = options.cflags_for_target
carrot2b549ca2013-02-19 22:45:25 +0000282 if options.cxxflags_for_target:
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800283 build_env['CXXFLAGS_FOR_TARGET'] = options.cxxflags_for_target
carrot255fd462013-02-19 22:43:16 +0000284 if options.ldflags:
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800285 build_env['LDFLAGS'] = options.ldflags
asharifc97199a2013-02-15 22:48:45 +0000286 if options.debug:
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800287 debug_flags = '-g3 -O0'
288 if 'CFLAGS' in build_env:
289 build_env['CFLAGS'] += ' %s' % (debug_flags)
cmticee59ac272013-02-19 20:20:09 +0000290 else:
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800291 build_env['CFLAGS'] = debug_flags
292 if 'CXXFLAGS' in build_env:
293 build_env['CXXFLAGS'] += ' %s' % (debug_flags)
cmticee59ac272013-02-19 20:20:09 +0000294 else:
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800295 build_env['CXXFLAGS'] = debug_flags
cmticecbc868a2013-02-21 22:52:46 +0000296 if options.extra_use_flags:
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800297 build_env['USE'] = options.extra_use_flags
bjanakiraman7f4a4852013-02-15 04:35:28 +0000298
asharif86968c42013-02-15 23:44:37 +0000299 # Create toolchain parts
carrote6f773c2013-02-19 22:34:44 +0000300 toolchain_parts = {}
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800301 for board in options.board.split(','):
asharif86968c42013-02-15 23:44:37 +0000302 if options.gcc_dir:
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800303 tp = ToolchainPart('gcc', gcc_dir, chromeos_root, board,
llozanof2726d22013-03-09 01:29:37 +0000304 not options.noincremental, build_env,
305 options.gcc_enable_ccache)
carrote6f773c2013-02-19 22:34:44 +0000306 toolchain_parts[tp.tag] = tp
307 tp.RunSetupBoardIfNecessary()
shenhan8e8b0c22013-02-19 22:34:16 +0000308 if options.binutils_dir:
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800309 tp = ToolchainPart('binutils', binutils_dir, chromeos_root, board,
shenhan8e8b0c22013-02-19 22:34:16 +0000310 not options.noincremental, build_env)
carrote6f773c2013-02-19 22:34:44 +0000311 toolchain_parts[tp.tag] = tp
312 tp.RunSetupBoardIfNecessary()
cmtice80d257f2013-02-15 23:44:51 +0000313 if options.gdb_dir:
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800314 tp = ToolchainPart('gdb', gdb_dir, chromeos_root, board,
cmtice80d257f2013-02-15 23:44:51 +0000315 not options.noincremental, build_env)
carrote6f773c2013-02-19 22:34:44 +0000316 toolchain_parts[tp.tag] = tp
317 tp.RunSetupBoardIfNecessary()
asharif86968c42013-02-15 23:44:37 +0000318
shenhanbecf6242013-02-19 20:43:32 +0000319 rv = 0
asharif86968c42013-02-15 23:44:37 +0000320 try:
carrote6f773c2013-02-19 22:34:44 +0000321 for tag in toolchain_parts:
322 tp = toolchain_parts[tag]
cmtice80d257f2013-02-15 23:44:51 +0000323 if options.mount_only or options.unmount_only:
324 tp.MountSources(options.unmount_only)
asharif86968c42013-02-15 23:44:37 +0000325 else:
shenhanbecf6242013-02-19 20:43:32 +0000326 rv = rv + tp.Build()
asharifc97199a2013-02-15 22:48:45 +0000327 finally:
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800328 print 'Exiting...'
llozano5fee82f2013-03-11 17:59:40 +0000329 return rv
asharif19c73dd2013-02-15 04:35:37 +0000330
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800331
332if __name__ == '__main__':
asharif2198c512013-02-15 09:21:35 +0000333 retval = Main(sys.argv)
334 sys.exit(retval)