blob: 34cba5439ebf5447f9127465c39a293f1e2a4a3a [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
7"""Script to build the ChromeOS toolchain.
8
9This script sets up the toolchain if you give it the gcctools directory.
10"""
11
12__author__ = "asharif@google.com (Ahmad Sharif)"
13
asharif80c6e552013-02-15 04:35:40 +000014import getpass
bjanakiraman7f4a4852013-02-15 04:35:28 +000015import optparse
asharif17621302013-02-15 04:46:35 +000016import os
bjanakiraman7f4a4852013-02-15 04:35:28 +000017import sys
asharifc97199a2013-02-15 22:48:45 +000018import tempfile
kbaclawski20082a02013-02-16 02:12:57 +000019
asharif252df0f2013-02-15 04:46:28 +000020import tc_enter_chroot
raymes01959ae2013-02-15 04:50:07 +000021from utils import command_executer
shenhanad803432013-02-16 03:14:51 +000022from utils import constants
kbaclawski20082a02013-02-16 02:12:57 +000023from utils import misc
bjanakiraman7f4a4852013-02-15 04:35:28 +000024
asharif5a9bb462013-02-15 04:50:57 +000025
asharifc97199a2013-02-15 22:48:45 +000026class ToolchainPart(object):
27 def __init__(self, name, source_path, chromeos_root, board, incremental,
llozanof2726d22013-03-09 01:29:37 +000028 build_env, gcc_enable_ccache=False):
asharifc97199a2013-02-15 22:48:45 +000029 self._name = name
kbaclawski20082a02013-02-16 02:12:57 +000030 self._source_path = misc.CanonicalizePath(source_path)
asharifc97199a2013-02-15 22:48:45 +000031 self._chromeos_root = chromeos_root
32 self._board = board
kbaclawski20082a02013-02-16 02:12:57 +000033 self._ctarget = misc.GetCtargetFromBoard(self._board,
asharif77bd80d2013-02-15 22:49:32 +000034 self._chromeos_root)
Rahul Chaudhry215c12f2014-11-04 15:18:47 -080035 self._gcc_libs_dest = misc.GetGccLibsDestForBoard(self._board,
36 self._chromeos_root)
carrote6f773c2013-02-19 22:34:44 +000037 self.tag = "%s-%s" % (name, self._ctarget)
asharifc97199a2013-02-15 22:48:45 +000038 self._ce = command_executer.GetCommandExecuter()
39 self._mask_file = os.path.join(
40 self._chromeos_root,
41 "chroot",
42 "etc/portage/package.mask/cross-%s" % self._ctarget)
43 self._new_mask_file = None
44
Han Shene4b6f222013-11-22 10:02:38 -080045 self._chroot_source_path = os.path.join(constants.MOUNTED_TOOLCHAIN_ROOT,
llozano85b37152013-02-16 03:14:57 +000046 self._name).lstrip("/")
asharifc97199a2013-02-15 22:48:45 +000047 self._incremental = incremental
48 self._build_env = build_env
llozanof2726d22013-03-09 01:29:37 +000049 self._gcc_enable_ccache = gcc_enable_ccache
asharifc97199a2013-02-15 22:48:45 +000050
51 def RunSetupBoardIfNecessary(self):
52 cross_symlink = os.path.join(
53 self._chromeos_root,
54 "chroot",
carrotccae6272013-02-19 22:34:51 +000055 "usr/local/bin/emerge-%s" % self._board)
asharifc97199a2013-02-15 22:48:45 +000056 if not os.path.exists(cross_symlink):
Rahul Chaudhry8ac4ec02014-11-01 09:31:15 -070057 command = ("%s/setup_board --board=%s" %
58 (misc.CHROMEOS_SCRIPTS_DIR, self._board))
asharifca3c6c12013-02-15 23:17:54 +000059 self._ce.ChrootRunCommand(self._chromeos_root, command)
asharifc97199a2013-02-15 22:48:45 +000060
61 def Build(self):
shenhanbecf6242013-02-19 20:43:32 +000062 rv = 1
asharifc97199a2013-02-15 22:48:45 +000063 try:
asharif7dd6d862013-02-15 23:17:46 +000064 self.UninstallTool()
asharifc97199a2013-02-15 22:48:45 +000065 self.MoveMaskFile()
cmtice80d257f2013-02-15 23:44:51 +000066 self.MountSources(False)
asharif9e3cf6e2013-02-16 03:13:38 +000067 self.RemoveCompiledFile()
shenhanbecf6242013-02-19 20:43:32 +000068 rv = self.BuildTool()
asharifc97199a2013-02-15 22:48:45 +000069 finally:
70 self.UnMoveMaskFile()
llozano9b84cb62013-03-11 21:08:31 +000071 return rv
asharifc97199a2013-02-15 22:48:45 +000072
73 def RemoveCompiledFile(self):
74 compiled_file = os.path.join(self._chromeos_root,
75 "chroot",
76 "var/tmp/portage/cross-%s" % self._ctarget,
77 "%s-9999" % self._name,
78 ".compiled")
asharif9e3cf6e2013-02-16 03:13:38 +000079 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 = []
84 mounted_source_path = os.path.join(self._chromeos_root,
85 "chroot",
86 self._chroot_source_path)
87 src_mp = tc_enter_chroot.MountPoint(
88 self._source_path,
89 mounted_source_path,
90 getpass.getuser(),
91 "ro")
92 mount_points.append(src_mp)
93
94 build_suffix = "build-%s" % self._ctarget
95 build_dir = "%s-%s" % (self._source_path, build_suffix)
96
97 if not self._incremental and os.path.exists(build_dir):
98 command = "rm -rf %s/*" % build_dir
99 self._ce.RunCommand(command)
100
101 # Create a -build directory for the objects.
102 command = "mkdir -p %s" % build_dir
103 self._ce.RunCommand(command)
104
105 mounted_build_dir = os.path.join(
106 self._chromeos_root, "chroot", "%s-%s" %
107 (self._chroot_source_path, build_suffix))
108 build_mp = tc_enter_chroot.MountPoint(
109 build_dir,
110 mounted_build_dir,
111 getpass.getuser())
112 mount_points.append(build_mp)
113
cmtice80d257f2013-02-15 23:44:51 +0000114 if unmount_source:
115 unmount_statuses = [mp.UnMount() == 0 for mp in mount_points]
asharifc97199a2013-02-15 22:48:45 +0000116 assert all(unmount_statuses), "Could not unmount all mount points!"
cmtice80d257f2013-02-15 23:44:51 +0000117 else:
118 mount_statuses = [mp.DoMount() == 0 for mp in mount_points]
119
120 if not all(mount_statuses):
121 mounted = [mp for mp, status in zip(mount_points, mount_statuses) if status]
122 unmount_statuses = [mp.UnMount() == 0 for mp in mounted]
123 assert all(unmount_statuses), "Could not unmount all mount points!"
124
asharifc97199a2013-02-15 22:48:45 +0000125
asharif7dd6d862013-02-15 23:17:46 +0000126 def UninstallTool(self):
127 command = "sudo CLEAN_DELAY=0 emerge -C cross-%s/%s" % (self._ctarget, self._name)
asharifca3c6c12013-02-15 23:17:54 +0000128 self._ce.ChrootRunCommand(self._chromeos_root, command)
asharif7dd6d862013-02-15 23:17:46 +0000129
asharifc97199a2013-02-15 22:48:45 +0000130 def BuildTool(self):
131 env = self._build_env
asharif9e499162013-02-16 02:41:39 +0000132 # FEATURES=buildpkg adds minutes of time so we disable it.
shenhanfdc0f572013-02-19 18:48:36 +0000133 # TODO(shenhan): keep '-sandbox' for a while for compatibility, then remove
134 # it after a while.
135 features = "nostrip userpriv userfetch -usersandbox -sandbox noclean -buildpkg"
asharifc97199a2013-02-15 22:48:45 +0000136 env["FEATURES"] = features
137
138 if self._incremental:
139 env["FEATURES"] += " keepwork"
140
cmticecbc868a2013-02-21 22:52:46 +0000141 if "USE" in env:
142 env["USE"] += " multislot mounted_%s" % self._name
143 else:
144 env["USE"] = "multislot mounted_%s" % self._name
145
llozanof2726d22013-03-09 01:29:37 +0000146 # Disable ccache in our compilers. cache may be problematic for us.
147 # It ignores compiler environments settings and it is not clear if
148 # the cache hit algorithm verifies all the compiler binaries or
149 # just the driver.
150 if self._name == "gcc" and not self._gcc_enable_ccache:
151 env["USE"] += " -wrapper_ccache"
152
asharifc97199a2013-02-15 22:48:45 +0000153 env["%s_SOURCE_PATH" % self._name.upper()] = (
154 os.path.join("/", self._chroot_source_path))
155 env["ACCEPT_KEYWORDS"] = "~*"
156 env_string = " ".join(["%s=\"%s\"" % var for var in env.items()])
157 command = "emerge =cross-%s/%s-9999" % (self._ctarget, self._name)
158 full_command = "sudo %s %s" % (env_string, command)
Luis Lozano4cea9de2013-03-20 12:32:56 -0700159 rv = self._ce.ChrootRunCommand(self._chromeos_root, full_command)
160 if rv != 0:
161 return rv
162 if self._name == "gcc":
Rahul Chaudhry215c12f2014-11-04 15:18:47 -0800163 command = ("sudo cp -r /usr/lib/gcc/%s %s" %
164 (self._ctarget, self._gcc_libs_dest))
Luis Lozano4cea9de2013-03-20 12:32:56 -0700165 rv = self._ce.ChrootRunCommand(self._chromeos_root, command)
166 return rv
asharifc97199a2013-02-15 22:48:45 +0000167
asharifc97199a2013-02-15 22:48:45 +0000168 def MoveMaskFile(self):
169 self._new_mask_file = None
170 if os.path.isfile(self._mask_file):
171 self._new_mask_file = tempfile.mktemp()
172 command = "sudo mv %s %s" % (self._mask_file, self._new_mask_file)
173 self._ce.RunCommand(command)
174
175 def UnMoveMaskFile(self):
176 if self._new_mask_file:
177 command = "sudo mv %s %s" % (self._new_mask_file, self._mask_file)
178 self._ce.RunCommand(command)
bjanakiraman7f4a4852013-02-15 04:35:28 +0000179
bjanakiraman7f4a4852013-02-15 04:35:28 +0000180
asharif0d3535a2013-02-15 04:50:33 +0000181def Main(argv):
asharif19c73dd2013-02-15 04:35:37 +0000182 """The main function."""
asharif5a9bb462013-02-15 04:50:57 +0000183 # Common initializations
asharif19c73dd2013-02-15 04:35:37 +0000184 parser = optparse.OptionParser()
asharifc97199a2013-02-15 22:48:45 +0000185 parser.add_option("-c",
186 "--chromeos_root",
187 dest="chromeos_root",
asharifbcdd4e52013-02-16 01:05:17 +0000188 default="../../",
asharifc97199a2013-02-15 22:48:45 +0000189 help=("ChromeOS root checkout directory"
190 " uses ../.. if none given."))
191 parser.add_option("-g",
192 "--gcc_dir",
193 dest="gcc_dir",
194 help="The directory where gcc resides.")
shenhan8e8b0c22013-02-19 22:34:16 +0000195 parser.add_option("--binutils_dir",
196 dest="binutils_dir",
197 help="The directory where binutils resides.")
cmtice80d257f2013-02-15 23:44:51 +0000198 parser.add_option("-x",
199 "--gdb_dir",
200 dest="gdb_dir",
201 help="The directory where gdb resides.")
asharifc97199a2013-02-15 22:48:45 +0000202 parser.add_option("-b",
203 "--board",
204 dest="board",
205 default="x86-agz",
206 help="The target board.")
207 parser.add_option("-n",
208 "--noincremental",
209 dest="noincremental",
210 default=False,
asharifd751e252013-02-15 04:35:52 +0000211 action="store_true",
asharifc97199a2013-02-15 22:48:45 +0000212 help="Use FEATURES=keepwork to do incremental builds.")
cmticee59ac272013-02-19 20:20:09 +0000213 parser.add_option("--cflags",
214 dest="cflags",
215 default="",
216 help="Build a compiler with specified CFLAGS")
217 parser.add_option("--cxxflags",
218 dest="cxxflags",
219 default="",
220 help="Build a compiler with specified CXXFLAGS")
carrot2b549ca2013-02-19 22:45:25 +0000221 parser.add_option("--cflags_for_target",
222 dest="cflags_for_target",
223 default="",
224 help="Build the target libraries with specified flags")
225 parser.add_option("--cxxflags_for_target",
226 dest="cxxflags_for_target",
227 default="",
228 help="Build the target libraries with specified flags")
cmticee59ac272013-02-19 20:20:09 +0000229 parser.add_option("--ldflags",
230 dest="ldflags",
231 default="",
232 help="Build a compiler with specified LDFLAGS")
asharifc97199a2013-02-15 22:48:45 +0000233 parser.add_option("-d",
234 "--debug",
235 dest="debug",
236 default=False,
asharifd751e252013-02-15 04:35:52 +0000237 action="store_true",
cmticee59ac272013-02-19 20:20:09 +0000238 help="Build a compiler with -g3 -O0 appended to both"
239 " CFLAGS and CXXFLAGS.")
asharif86968c42013-02-15 23:44:37 +0000240 parser.add_option("-m",
241 "--mount_only",
242 dest="mount_only",
243 default=False,
244 action="store_true",
245 help="Just mount the tool directories.")
cmtice80d257f2013-02-15 23:44:51 +0000246 parser.add_option("-u",
247 "--unmount_only",
248 dest="unmount_only",
249 default=False,
250 action="store_true",
251 help="Just unmount the tool directories.")
cmticecbc868a2013-02-21 22:52:46 +0000252 parser.add_option("--extra_use_flags",
253 dest="extra_use_flags",
254 default="",
255 help="Extra flag for USE, to be passed to the ebuild. "
256 "('multislot' and 'mounted_<tool>' are always passed.)")
llozanof2726d22013-03-09 01:29:37 +0000257 parser.add_option("--gcc_enable_ccache",
258 dest="gcc_enable_ccache",
259 default=False,
260 action="store_true",
261 help="Enable ccache for the gcc invocations")
bjanakiraman7f4a4852013-02-15 04:35:28 +0000262
asharifc97199a2013-02-15 22:48:45 +0000263 options, _ = parser.parse_args(argv)
asharif17621302013-02-15 04:46:35 +0000264
kbaclawski20082a02013-02-16 02:12:57 +0000265 chromeos_root = misc.CanonicalizePath(options.chromeos_root)
cmtice80d257f2013-02-15 23:44:51 +0000266 if options.gcc_dir:
kbaclawski20082a02013-02-16 02:12:57 +0000267 gcc_dir = misc.CanonicalizePath(options.gcc_dir)
Luis Lozano4cea9de2013-03-20 12:32:56 -0700268 assert gcc_dir and os.path.isdir(gcc_dir), "gcc_dir does not exist!"
shenhan8e8b0c22013-02-19 22:34:16 +0000269 if options.binutils_dir:
270 binutils_dir = misc.CanonicalizePath(options.binutils_dir)
Luis Lozano4cea9de2013-03-20 12:32:56 -0700271 assert os.path.isdir(binutils_dir), "binutils_dir does not exist!"
cmtice80d257f2013-02-15 23:44:51 +0000272 if options.gdb_dir:
kbaclawski20082a02013-02-16 02:12:57 +0000273 gdb_dir = misc.CanonicalizePath(options.gdb_dir)
Luis Lozano4cea9de2013-03-20 12:32:56 -0700274 assert os.path.isdir(gdb_dir), "gdb_dir does not exist!"
cmtice80d257f2013-02-15 23:44:51 +0000275 if options.unmount_only:
276 options.mount_only = False
277 elif options.mount_only:
278 options.unmount_only = False
asharifc97199a2013-02-15 22:48:45 +0000279 build_env = {}
cmticee59ac272013-02-19 20:20:09 +0000280 if options.cflags:
carrot255fd462013-02-19 22:43:16 +0000281 build_env["CFLAGS"] = "`portageq envvar CFLAGS` " + options.cflags
cmticee59ac272013-02-19 20:20:09 +0000282 if options.cxxflags:
carrot255fd462013-02-19 22:43:16 +0000283 build_env["CXXFLAGS"] = "`portageq envvar CXXFLAGS` " + options.cxxflags
carrot2b549ca2013-02-19 22:45:25 +0000284 if options.cflags_for_target:
285 build_env["CFLAGS_FOR_TARGET"] = options.cflags_for_target
286 if options.cxxflags_for_target:
287 build_env["CXXFLAGS_FOR_TARGET"] = options.cxxflags_for_target
carrot255fd462013-02-19 22:43:16 +0000288 if options.ldflags:
cmticee59ac272013-02-19 20:20:09 +0000289 build_env["LDFLAGS"] = options.ldflags
asharifc97199a2013-02-15 22:48:45 +0000290 if options.debug:
291 debug_flags = "-g3 -O0"
cmticee59ac272013-02-19 20:20:09 +0000292 if "CFLAGS" in build_env:
293 build_env["CFLAGS"] += " %s" % (debug_flags)
294 else:
295 build_env["CFLAGS"] = debug_flags
296 if "CXXFLAGS" in build_env:
297 build_env["CXXFLAGS"] += " %s" % (debug_flags)
298 else:
299 build_env["CXXFLAGS"] = debug_flags
cmticecbc868a2013-02-21 22:52:46 +0000300 if options.extra_use_flags:
301 build_env["USE"] = options.extra_use_flags
bjanakiraman7f4a4852013-02-15 04:35:28 +0000302
asharif86968c42013-02-15 23:44:37 +0000303 # Create toolchain parts
carrote6f773c2013-02-19 22:34:44 +0000304 toolchain_parts = {}
asharif86968c42013-02-15 23:44:37 +0000305 for board in options.board.split(","):
306 if options.gcc_dir:
asharifc97199a2013-02-15 22:48:45 +0000307 tp = ToolchainPart("gcc", gcc_dir, chromeos_root, board,
llozanof2726d22013-03-09 01:29:37 +0000308 not options.noincremental, build_env,
309 options.gcc_enable_ccache)
carrote6f773c2013-02-19 22:34:44 +0000310 toolchain_parts[tp.tag] = tp
311 tp.RunSetupBoardIfNecessary()
shenhan8e8b0c22013-02-19 22:34:16 +0000312 if options.binutils_dir:
313 tp = ToolchainPart("binutils", binutils_dir, chromeos_root, board,
314 not options.noincremental, build_env)
carrote6f773c2013-02-19 22:34:44 +0000315 toolchain_parts[tp.tag] = tp
316 tp.RunSetupBoardIfNecessary()
cmtice80d257f2013-02-15 23:44:51 +0000317 if options.gdb_dir:
318 tp = ToolchainPart("gdb", gdb_dir, chromeos_root, board,
319 not options.noincremental, build_env)
carrote6f773c2013-02-19 22:34:44 +0000320 toolchain_parts[tp.tag] = tp
321 tp.RunSetupBoardIfNecessary()
asharif86968c42013-02-15 23:44:37 +0000322
shenhanbecf6242013-02-19 20:43:32 +0000323 rv = 0
asharif86968c42013-02-15 23:44:37 +0000324 try:
carrote6f773c2013-02-19 22:34:44 +0000325 for tag in toolchain_parts:
326 tp = toolchain_parts[tag]
cmtice80d257f2013-02-15 23:44:51 +0000327 if options.mount_only or options.unmount_only:
328 tp.MountSources(options.unmount_only)
asharif86968c42013-02-15 23:44:37 +0000329 else:
shenhanbecf6242013-02-19 20:43:32 +0000330 rv = rv + tp.Build()
asharifc97199a2013-02-15 22:48:45 +0000331 finally:
332 print "Exiting..."
llozano5fee82f2013-03-11 17:59:40 +0000333 return rv
asharif19c73dd2013-02-15 04:35:37 +0000334
335if __name__ == "__main__":
asharif2198c512013-02-15 09:21:35 +0000336 retval = Main(sys.argv)
337 sys.exit(retval)