blob: 8eed86ee63cd44277b108b3184f8ff1390b671e1 [file] [log] [blame]
Zhizhou Yang81d651f2020-02-10 16:51:20 -08001#!/usr/bin/env python3
2# -*- coding: utf-8 -*-
George Burgess IV2124be52022-04-21 10:27:37 -07003# Copyright 2010 The ChromiumOS Authors. All rights reserved.
Rahul Chaudhry8ac4ec02014-11-01 09:31:15 -07004# Use of this source code is governed by a BSD-style license that can be
5# found in the LICENSE file.
Zhizhou Yang81d651f2020-02-10 16:51:20 -08006
bjanakiraman7f4a4852013-02-15 04:35:28 +00007"""Script to build the ChromeOS toolchain.
8
9This script sets up the toolchain if you give it the gcctools directory.
10"""
11
Caroline Tice88272d42016-01-13 09:48:29 -080012from __future__ import print_function
13
George Burgess IV74bd3802022-09-02 16:59:27 -070014
15__author__ = "asharif@google.com (Ahmad Sharif)"
bjanakiraman7f4a4852013-02-15 04:35:28 +000016
Caroline Tice88272d42016-01-13 09:48:29 -080017import argparse
asharif80c6e552013-02-15 04:35:40 +000018import getpass
asharif17621302013-02-15 04:46:35 +000019import os
bjanakiraman7f4a4852013-02-15 04:35:28 +000020import sys
asharifc97199a2013-02-15 22:48:45 +000021import tempfile
kbaclawski20082a02013-02-16 02:12:57 +000022
Caroline Tice88272d42016-01-13 09:48:29 -080023from cros_utils import command_executer
24from cros_utils import constants
25from cros_utils import misc
George Burgess IV74bd3802022-09-02 16:59:27 -070026import tc_enter_chroot
bjanakiraman7f4a4852013-02-15 04:35:28 +000027
asharif5a9bb462013-02-15 04:50:57 +000028
asharifc97199a2013-02-15 22:48:45 +000029class ToolchainPart(object):
George Burgess IV74bd3802022-09-02 16:59:27 -070030 """Class to hold the toolchain pieces."""
Luis Lozanof2a3ef42015-12-15 13:49:30 -080031
George Burgess IV74bd3802022-09-02 16:59:27 -070032 def __init__(
33 self,
34 name,
35 source_path,
36 chromeos_root,
37 board,
38 incremental,
39 build_env,
40 gcc_enable_ccache=False,
41 ):
42 self._name = name
43 self._source_path = misc.CanonicalizePath(source_path)
44 self._chromeos_root = chromeos_root
45 self._board = board
46 self._ctarget = misc.GetCtargetFromBoard(
47 self._board, self._chromeos_root
48 )
49 self._gcc_libs_dest = misc.GetGccLibsDestForBoard(
50 self._board, self._chromeos_root
51 )
52 self.tag = "%s-%s" % (name, self._ctarget)
53 self._ce = command_executer.GetCommandExecuter()
54 self._mask_file = os.path.join(
55 self._chromeos_root,
56 "chroot",
57 "etc/portage/package.mask/cross-%s" % self._ctarget,
58 )
59 self._new_mask_file = None
asharifc97199a2013-02-15 22:48:45 +000060
George Burgess IV74bd3802022-09-02 16:59:27 -070061 self._chroot_source_path = os.path.join(
62 constants.MOUNTED_TOOLCHAIN_ROOT, self._name
63 ).lstrip("/")
64 self._incremental = incremental
65 self._build_env = build_env
66 self._gcc_enable_ccache = gcc_enable_ccache
asharifc97199a2013-02-15 22:48:45 +000067
George Burgess IV74bd3802022-09-02 16:59:27 -070068 def RunSetupBoardIfNecessary(self):
69 cross_symlink = os.path.join(
70 self._chromeos_root,
71 "chroot",
72 "usr/local/bin/emerge-%s" % self._board,
73 )
74 if not os.path.exists(cross_symlink):
75 command = "setup_board --board=%s" % self._board
76 self._ce.ChrootRunCommand(self._chromeos_root, command)
asharifc97199a2013-02-15 22:48:45 +000077
George Burgess IV74bd3802022-09-02 16:59:27 -070078 def Build(self):
79 rv = 1
80 try:
81 self.UninstallTool()
82 self.MoveMaskFile()
83 self.MountSources(False)
84 self.RemoveCompiledFile()
85 rv = self.BuildTool()
86 finally:
87 self.UnMoveMaskFile()
88 return rv
asharifc97199a2013-02-15 22:48:45 +000089
George Burgess IV74bd3802022-09-02 16:59:27 -070090 def RemoveCompiledFile(self):
91 compiled_file = os.path.join(
92 self._chromeos_root,
93 "chroot",
94 "var/tmp/portage/cross-%s" % self._ctarget,
95 "%s-9999" % self._name,
96 ".compiled",
97 )
98 command = "rm -f %s" % compiled_file
99 self._ce.RunCommand(command)
asharifc97199a2013-02-15 22:48:45 +0000100
George Burgess IV74bd3802022-09-02 16:59:27 -0700101 def MountSources(self, unmount_source):
102 mount_points = []
103 mounted_source_path = os.path.join(
104 self._chromeos_root, "chroot", self._chroot_source_path
105 )
106 src_mp = tc_enter_chroot.MountPoint(
107 self._source_path, mounted_source_path, getpass.getuser(), "ro"
108 )
109 mount_points.append(src_mp)
asharifc97199a2013-02-15 22:48:45 +0000110
George Burgess IV74bd3802022-09-02 16:59:27 -0700111 build_suffix = "build-%s" % self._ctarget
112 build_dir = "%s-%s" % (self._source_path, build_suffix)
asharifc97199a2013-02-15 22:48:45 +0000113
George Burgess IV74bd3802022-09-02 16:59:27 -0700114 if not self._incremental and os.path.exists(build_dir):
115 command = "rm -rf %s/*" % build_dir
116 self._ce.RunCommand(command)
asharifc97199a2013-02-15 22:48:45 +0000117
George Burgess IV74bd3802022-09-02 16:59:27 -0700118 # Create a -build directory for the objects.
119 command = "mkdir -p %s" % build_dir
120 self._ce.RunCommand(command)
asharifc97199a2013-02-15 22:48:45 +0000121
George Burgess IV74bd3802022-09-02 16:59:27 -0700122 mounted_build_dir = os.path.join(
123 self._chromeos_root,
124 "chroot",
125 "%s-%s" % (self._chroot_source_path, build_suffix),
126 )
127 build_mp = tc_enter_chroot.MountPoint(
128 build_dir, mounted_build_dir, getpass.getuser()
129 )
130 mount_points.append(build_mp)
asharifc97199a2013-02-15 22:48:45 +0000131
George Burgess IV74bd3802022-09-02 16:59:27 -0700132 if unmount_source:
133 unmount_statuses = [mp.UnMount() == 0 for mp in mount_points]
134 assert all(unmount_statuses), "Could not unmount all mount points!"
135 else:
136 mount_statuses = [mp.DoMount() == 0 for mp in mount_points]
cmtice80d257f2013-02-15 23:44:51 +0000137
George Burgess IV74bd3802022-09-02 16:59:27 -0700138 if not all(mount_statuses):
139 mounted = [
140 mp
141 for mp, status in zip(mount_points, mount_statuses)
142 if status
143 ]
144 unmount_statuses = [mp.UnMount() == 0 for mp in mounted]
145 assert all(
146 unmount_statuses
147 ), "Could not unmount all mount points!"
asharifc97199a2013-02-15 22:48:45 +0000148
George Burgess IV74bd3802022-09-02 16:59:27 -0700149 def UninstallTool(self):
150 command = "sudo CLEAN_DELAY=0 emerge -C cross-%s/%s" % (
151 self._ctarget,
152 self._name,
153 )
154 self._ce.ChrootRunCommand(self._chromeos_root, command)
asharif7dd6d862013-02-15 23:17:46 +0000155
George Burgess IV74bd3802022-09-02 16:59:27 -0700156 def BuildTool(self):
157 env = self._build_env
158 # FEATURES=buildpkg adds minutes of time so we disable it.
159 # TODO(shenhan): keep '-sandbox' for a while for compatibility, then remove
160 # it after a while.
161 features = (
162 "nostrip userpriv userfetch -usersandbox -sandbox noclean "
163 "-buildpkg"
164 )
165 env["FEATURES"] = features
asharifc97199a2013-02-15 22:48:45 +0000166
George Burgess IV74bd3802022-09-02 16:59:27 -0700167 if self._incremental:
168 env["FEATURES"] += " keepwork"
asharifc97199a2013-02-15 22:48:45 +0000169
George Burgess IV74bd3802022-09-02 16:59:27 -0700170 if "USE" in env:
171 env["USE"] += " multislot mounted_%s" % self._name
172 else:
173 env["USE"] = "multislot mounted_%s" % self._name
cmticecbc868a2013-02-21 22:52:46 +0000174
George Burgess IV74bd3802022-09-02 16:59:27 -0700175 # Disable ccache in our compilers. cache may be problematic for us.
176 # It ignores compiler environments settings and it is not clear if
177 # the cache hit algorithm verifies all the compiler binaries or
178 # just the driver.
179 if self._name == "gcc" and not self._gcc_enable_ccache:
180 env["USE"] += " -wrapper_ccache"
llozanof2726d22013-03-09 01:29:37 +0000181
George Burgess IV74bd3802022-09-02 16:59:27 -0700182 env["%s_SOURCE_PATH" % self._name.upper()] = os.path.join(
183 "/", self._chroot_source_path
184 )
185 env["ACCEPT_KEYWORDS"] = "~*"
186 env_string = " ".join(['%s="%s"' % var for var in env.items()])
187 command = "emerge =cross-%s/%s-9999" % (self._ctarget, self._name)
188 full_command = "sudo %s %s" % (env_string, command)
189 rv = self._ce.ChrootRunCommand(self._chromeos_root, full_command)
190 if rv != 0:
191 return rv
192 if self._name == "gcc":
193 command = "sudo cp -r /usr/lib/gcc/%s %s" % (
194 self._ctarget,
195 self._gcc_libs_dest,
196 )
197 rv = self._ce.ChrootRunCommand(self._chromeos_root, command)
198 return rv
asharifc97199a2013-02-15 22:48:45 +0000199
George Burgess IV74bd3802022-09-02 16:59:27 -0700200 def MoveMaskFile(self):
201 self._new_mask_file = None
202 if os.path.isfile(self._mask_file):
203 self._new_mask_file = tempfile.mktemp()
204 command = "sudo mv %s %s" % (self._mask_file, self._new_mask_file)
205 self._ce.RunCommand(command)
asharifc97199a2013-02-15 22:48:45 +0000206
George Burgess IV74bd3802022-09-02 16:59:27 -0700207 def UnMoveMaskFile(self):
208 if self._new_mask_file:
209 command = "sudo mv %s %s" % (self._new_mask_file, self._mask_file)
210 self._ce.RunCommand(command)
bjanakiraman7f4a4852013-02-15 04:35:28 +0000211
bjanakiraman7f4a4852013-02-15 04:35:28 +0000212
asharif0d3535a2013-02-15 04:50:33 +0000213def Main(argv):
George Burgess IV74bd3802022-09-02 16:59:27 -0700214 """The main function."""
215 # Common initializations
216 parser = argparse.ArgumentParser()
217 parser.add_argument(
218 "-c",
219 "--chromeos_root",
220 dest="chromeos_root",
221 default="../../",
222 help=("ChromeOS root checkout directory" " uses ../.. if none given."),
223 )
224 parser.add_argument(
225 "-g",
226 "--gcc_dir",
227 dest="gcc_dir",
228 help="The directory where gcc resides.",
229 )
230 parser.add_argument(
231 "--binutils_dir",
232 dest="binutils_dir",
233 help="The directory where binutils resides.",
234 )
235 parser.add_argument(
236 "-x",
237 "--gdb_dir",
238 dest="gdb_dir",
239 help="The directory where gdb resides.",
240 )
241 parser.add_argument(
242 "-b",
243 "--board",
244 dest="board",
245 default="x86-alex",
246 help="The target board.",
247 )
248 parser.add_argument(
249 "-n",
250 "--noincremental",
251 dest="noincremental",
252 default=False,
253 action="store_true",
254 help="Use FEATURES=keepwork to do incremental builds.",
255 )
256 parser.add_argument(
257 "--cflags",
258 dest="cflags",
259 default="",
260 help="Build a compiler with specified CFLAGS",
261 )
262 parser.add_argument(
263 "--cxxflags",
264 dest="cxxflags",
265 default="",
266 help="Build a compiler with specified CXXFLAGS",
267 )
268 parser.add_argument(
269 "--cflags_for_target",
270 dest="cflags_for_target",
271 default="",
272 help="Build the target libraries with specified flags",
273 )
274 parser.add_argument(
275 "--cxxflags_for_target",
276 dest="cxxflags_for_target",
277 default="",
278 help="Build the target libraries with specified flags",
279 )
280 parser.add_argument(
281 "--ldflags",
282 dest="ldflags",
283 default="",
284 help="Build a compiler with specified LDFLAGS",
285 )
286 parser.add_argument(
287 "-d",
288 "--debug",
289 dest="debug",
290 default=False,
291 action="store_true",
292 help="Build a compiler with -g3 -O0 appended to both"
293 " CFLAGS and CXXFLAGS.",
294 )
295 parser.add_argument(
296 "-m",
297 "--mount_only",
298 dest="mount_only",
299 default=False,
300 action="store_true",
301 help="Just mount the tool directories.",
302 )
303 parser.add_argument(
304 "-u",
305 "--unmount_only",
306 dest="unmount_only",
307 default=False,
308 action="store_true",
309 help="Just unmount the tool directories.",
310 )
311 parser.add_argument(
312 "--extra_use_flags",
313 dest="extra_use_flags",
314 default="",
315 help="Extra flag for USE, to be passed to the ebuild. "
316 "('multislot' and 'mounted_<tool>' are always passed.)",
317 )
318 parser.add_argument(
319 "--gcc_enable_ccache",
320 dest="gcc_enable_ccache",
321 default=False,
322 action="store_true",
323 help="Enable ccache for the gcc invocations",
324 )
bjanakiraman7f4a4852013-02-15 04:35:28 +0000325
George Burgess IV74bd3802022-09-02 16:59:27 -0700326 options = parser.parse_args(argv)
asharif17621302013-02-15 04:46:35 +0000327
George Burgess IV74bd3802022-09-02 16:59:27 -0700328 chromeos_root = misc.CanonicalizePath(options.chromeos_root)
asharif86968c42013-02-15 23:44:37 +0000329 if options.gcc_dir:
George Burgess IV74bd3802022-09-02 16:59:27 -0700330 gcc_dir = misc.CanonicalizePath(options.gcc_dir)
331 assert gcc_dir and os.path.isdir(gcc_dir), "gcc_dir does not exist!"
shenhan8e8b0c22013-02-19 22:34:16 +0000332 if options.binutils_dir:
George Burgess IV74bd3802022-09-02 16:59:27 -0700333 binutils_dir = misc.CanonicalizePath(options.binutils_dir)
334 assert os.path.isdir(binutils_dir), "binutils_dir does not exist!"
cmtice80d257f2013-02-15 23:44:51 +0000335 if options.gdb_dir:
George Burgess IV74bd3802022-09-02 16:59:27 -0700336 gdb_dir = misc.CanonicalizePath(options.gdb_dir)
337 assert os.path.isdir(gdb_dir), "gdb_dir does not exist!"
338 if options.unmount_only:
339 options.mount_only = False
340 elif options.mount_only:
341 options.unmount_only = False
342 build_env = {}
343 if options.cflags:
344 build_env["CFLAGS"] = "`portageq envvar CFLAGS` " + options.cflags
345 if options.cxxflags:
346 build_env["CXXFLAGS"] = "`portageq envvar CXXFLAGS` " + options.cxxflags
347 if options.cflags_for_target:
348 build_env["CFLAGS_FOR_TARGET"] = options.cflags_for_target
349 if options.cxxflags_for_target:
350 build_env["CXXFLAGS_FOR_TARGET"] = options.cxxflags_for_target
351 if options.ldflags:
352 build_env["LDFLAGS"] = options.ldflags
353 if options.debug:
354 debug_flags = "-g3 -O0"
355 if "CFLAGS" in build_env:
356 build_env["CFLAGS"] += " %s" % (debug_flags)
357 else:
358 build_env["CFLAGS"] = debug_flags
359 if "CXXFLAGS" in build_env:
360 build_env["CXXFLAGS"] += " %s" % (debug_flags)
361 else:
362 build_env["CXXFLAGS"] = debug_flags
363 if options.extra_use_flags:
364 build_env["USE"] = options.extra_use_flags
asharif86968c42013-02-15 23:44:37 +0000365
George Burgess IV74bd3802022-09-02 16:59:27 -0700366 # Create toolchain parts
367 toolchain_parts = {}
368 for board in options.board.split(","):
369 if options.gcc_dir:
370 tp = ToolchainPart(
371 "gcc",
372 gcc_dir,
373 chromeos_root,
374 board,
375 not options.noincremental,
376 build_env,
377 options.gcc_enable_ccache,
378 )
379 toolchain_parts[tp.tag] = tp
380 tp.RunSetupBoardIfNecessary()
381 if options.binutils_dir:
382 tp = ToolchainPart(
383 "binutils",
384 binutils_dir,
385 chromeos_root,
386 board,
387 not options.noincremental,
388 build_env,
389 )
390 toolchain_parts[tp.tag] = tp
391 tp.RunSetupBoardIfNecessary()
392 if options.gdb_dir:
393 tp = ToolchainPart(
394 "gdb",
395 gdb_dir,
396 chromeos_root,
397 board,
398 not options.noincremental,
399 build_env,
400 )
401 toolchain_parts[tp.tag] = tp
402 tp.RunSetupBoardIfNecessary()
403
404 rv = 0
405 try:
406 for tag in toolchain_parts:
407 tp = toolchain_parts[tag]
408 if options.mount_only or options.unmount_only:
409 tp.MountSources(options.unmount_only)
410 else:
411 rv = rv + tp.Build()
412 finally:
413 print("Exiting...")
414 return rv
asharif19c73dd2013-02-15 04:35:37 +0000415
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800416
George Burgess IV74bd3802022-09-02 16:59:27 -0700417if __name__ == "__main__":
418 retval = Main(sys.argv[1:])
419 sys.exit(retval)