blob: 08f80e69cc4f9457103b95572160af859d4f9fb3 [file] [log] [blame]
Zhizhou Yang81d651f2020-02-10 16:51:20 -08001#!/usr/bin/env python3
2# -*- coding: utf-8 -*-
Mike Frysingerfdcd39d2022-09-13 14:19:58 -04003# Copyright 2010 The ChromiumOS Authors
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
George Burgess IV74bd3802022-09-02 16:59:27 -070012
13__author__ = "asharif@google.com (Ahmad Sharif)"
bjanakiraman7f4a4852013-02-15 04:35:28 +000014
Caroline Tice88272d42016-01-13 09:48:29 -080015import argparse
asharif80c6e552013-02-15 04:35:40 +000016import getpass
asharif17621302013-02-15 04:46:35 +000017import os
bjanakiraman7f4a4852013-02-15 04:35:28 +000018import sys
asharifc97199a2013-02-15 22:48:45 +000019import tempfile
kbaclawski20082a02013-02-16 02:12:57 +000020
Caroline Tice88272d42016-01-13 09:48:29 -080021from cros_utils import command_executer
22from cros_utils import constants
23from cros_utils import misc
George Burgess IV74bd3802022-09-02 16:59:27 -070024import tc_enter_chroot
bjanakiraman7f4a4852013-02-15 04:35:28 +000025
asharif5a9bb462013-02-15 04:50:57 +000026
asharifc97199a2013-02-15 22:48:45 +000027class ToolchainPart(object):
George Burgess IV74bd3802022-09-02 16:59:27 -070028 """Class to hold the toolchain pieces."""
Luis Lozanof2a3ef42015-12-15 13:49:30 -080029
George Burgess IV74bd3802022-09-02 16:59:27 -070030 def __init__(
31 self,
32 name,
33 source_path,
34 chromeos_root,
35 board,
36 incremental,
37 build_env,
38 gcc_enable_ccache=False,
39 ):
40 self._name = name
41 self._source_path = misc.CanonicalizePath(source_path)
42 self._chromeos_root = chromeos_root
43 self._board = board
44 self._ctarget = misc.GetCtargetFromBoard(
45 self._board, self._chromeos_root
46 )
47 self._gcc_libs_dest = misc.GetGccLibsDestForBoard(
48 self._board, self._chromeos_root
49 )
50 self.tag = "%s-%s" % (name, self._ctarget)
51 self._ce = command_executer.GetCommandExecuter()
52 self._mask_file = os.path.join(
53 self._chromeos_root,
54 "chroot",
55 "etc/portage/package.mask/cross-%s" % self._ctarget,
56 )
57 self._new_mask_file = None
asharifc97199a2013-02-15 22:48:45 +000058
George Burgess IV74bd3802022-09-02 16:59:27 -070059 self._chroot_source_path = os.path.join(
60 constants.MOUNTED_TOOLCHAIN_ROOT, self._name
61 ).lstrip("/")
62 self._incremental = incremental
63 self._build_env = build_env
64 self._gcc_enable_ccache = gcc_enable_ccache
asharifc97199a2013-02-15 22:48:45 +000065
George Burgess IV74bd3802022-09-02 16:59:27 -070066 def RunSetupBoardIfNecessary(self):
67 cross_symlink = os.path.join(
68 self._chromeos_root,
69 "chroot",
70 "usr/local/bin/emerge-%s" % self._board,
71 )
72 if not os.path.exists(cross_symlink):
73 command = "setup_board --board=%s" % self._board
74 self._ce.ChrootRunCommand(self._chromeos_root, command)
asharifc97199a2013-02-15 22:48:45 +000075
George Burgess IV74bd3802022-09-02 16:59:27 -070076 def Build(self):
77 rv = 1
78 try:
79 self.UninstallTool()
80 self.MoveMaskFile()
81 self.MountSources(False)
82 self.RemoveCompiledFile()
83 rv = self.BuildTool()
84 finally:
85 self.UnMoveMaskFile()
86 return rv
asharifc97199a2013-02-15 22:48:45 +000087
George Burgess IV74bd3802022-09-02 16:59:27 -070088 def RemoveCompiledFile(self):
89 compiled_file = os.path.join(
90 self._chromeos_root,
91 "chroot",
92 "var/tmp/portage/cross-%s" % self._ctarget,
93 "%s-9999" % self._name,
94 ".compiled",
95 )
96 command = "rm -f %s" % compiled_file
97 self._ce.RunCommand(command)
asharifc97199a2013-02-15 22:48:45 +000098
George Burgess IV74bd3802022-09-02 16:59:27 -070099 def MountSources(self, unmount_source):
100 mount_points = []
101 mounted_source_path = os.path.join(
102 self._chromeos_root, "chroot", self._chroot_source_path
103 )
104 src_mp = tc_enter_chroot.MountPoint(
105 self._source_path, mounted_source_path, getpass.getuser(), "ro"
106 )
107 mount_points.append(src_mp)
asharifc97199a2013-02-15 22:48:45 +0000108
George Burgess IV74bd3802022-09-02 16:59:27 -0700109 build_suffix = "build-%s" % self._ctarget
110 build_dir = "%s-%s" % (self._source_path, build_suffix)
asharifc97199a2013-02-15 22:48:45 +0000111
George Burgess IV74bd3802022-09-02 16:59:27 -0700112 if not self._incremental and os.path.exists(build_dir):
113 command = "rm -rf %s/*" % build_dir
114 self._ce.RunCommand(command)
asharifc97199a2013-02-15 22:48:45 +0000115
George Burgess IV74bd3802022-09-02 16:59:27 -0700116 # Create a -build directory for the objects.
117 command = "mkdir -p %s" % build_dir
118 self._ce.RunCommand(command)
asharifc97199a2013-02-15 22:48:45 +0000119
George Burgess IV74bd3802022-09-02 16:59:27 -0700120 mounted_build_dir = os.path.join(
121 self._chromeos_root,
122 "chroot",
123 "%s-%s" % (self._chroot_source_path, build_suffix),
124 )
125 build_mp = tc_enter_chroot.MountPoint(
126 build_dir, mounted_build_dir, getpass.getuser()
127 )
128 mount_points.append(build_mp)
asharifc97199a2013-02-15 22:48:45 +0000129
George Burgess IV74bd3802022-09-02 16:59:27 -0700130 if unmount_source:
131 unmount_statuses = [mp.UnMount() == 0 for mp in mount_points]
132 assert all(unmount_statuses), "Could not unmount all mount points!"
133 else:
134 mount_statuses = [mp.DoMount() == 0 for mp in mount_points]
cmtice80d257f2013-02-15 23:44:51 +0000135
George Burgess IV74bd3802022-09-02 16:59:27 -0700136 if not all(mount_statuses):
137 mounted = [
138 mp
139 for mp, status in zip(mount_points, mount_statuses)
140 if status
141 ]
142 unmount_statuses = [mp.UnMount() == 0 for mp in mounted]
143 assert all(
144 unmount_statuses
145 ), "Could not unmount all mount points!"
asharifc97199a2013-02-15 22:48:45 +0000146
George Burgess IV74bd3802022-09-02 16:59:27 -0700147 def UninstallTool(self):
148 command = "sudo CLEAN_DELAY=0 emerge -C cross-%s/%s" % (
149 self._ctarget,
150 self._name,
151 )
152 self._ce.ChrootRunCommand(self._chromeos_root, command)
asharif7dd6d862013-02-15 23:17:46 +0000153
George Burgess IV74bd3802022-09-02 16:59:27 -0700154 def BuildTool(self):
155 env = self._build_env
156 # FEATURES=buildpkg adds minutes of time so we disable it.
157 # TODO(shenhan): keep '-sandbox' for a while for compatibility, then remove
158 # it after a while.
159 features = (
160 "nostrip userpriv userfetch -usersandbox -sandbox noclean "
161 "-buildpkg"
162 )
163 env["FEATURES"] = features
asharifc97199a2013-02-15 22:48:45 +0000164
George Burgess IV74bd3802022-09-02 16:59:27 -0700165 if self._incremental:
166 env["FEATURES"] += " keepwork"
asharifc97199a2013-02-15 22:48:45 +0000167
George Burgess IV74bd3802022-09-02 16:59:27 -0700168 if "USE" in env:
169 env["USE"] += " multislot mounted_%s" % self._name
170 else:
171 env["USE"] = "multislot mounted_%s" % self._name
cmticecbc868a2013-02-21 22:52:46 +0000172
George Burgess IV74bd3802022-09-02 16:59:27 -0700173 # Disable ccache in our compilers. cache may be problematic for us.
174 # It ignores compiler environments settings and it is not clear if
175 # the cache hit algorithm verifies all the compiler binaries or
176 # just the driver.
177 if self._name == "gcc" and not self._gcc_enable_ccache:
178 env["USE"] += " -wrapper_ccache"
llozanof2726d22013-03-09 01:29:37 +0000179
George Burgess IV74bd3802022-09-02 16:59:27 -0700180 env["%s_SOURCE_PATH" % self._name.upper()] = os.path.join(
181 "/", self._chroot_source_path
182 )
183 env["ACCEPT_KEYWORDS"] = "~*"
184 env_string = " ".join(['%s="%s"' % var for var in env.items()])
185 command = "emerge =cross-%s/%s-9999" % (self._ctarget, self._name)
186 full_command = "sudo %s %s" % (env_string, command)
187 rv = self._ce.ChrootRunCommand(self._chromeos_root, full_command)
188 if rv != 0:
189 return rv
190 if self._name == "gcc":
191 command = "sudo cp -r /usr/lib/gcc/%s %s" % (
192 self._ctarget,
193 self._gcc_libs_dest,
194 )
195 rv = self._ce.ChrootRunCommand(self._chromeos_root, command)
196 return rv
asharifc97199a2013-02-15 22:48:45 +0000197
George Burgess IV74bd3802022-09-02 16:59:27 -0700198 def MoveMaskFile(self):
199 self._new_mask_file = None
200 if os.path.isfile(self._mask_file):
201 self._new_mask_file = tempfile.mktemp()
202 command = "sudo mv %s %s" % (self._mask_file, self._new_mask_file)
203 self._ce.RunCommand(command)
asharifc97199a2013-02-15 22:48:45 +0000204
George Burgess IV74bd3802022-09-02 16:59:27 -0700205 def UnMoveMaskFile(self):
206 if self._new_mask_file:
207 command = "sudo mv %s %s" % (self._new_mask_file, self._mask_file)
208 self._ce.RunCommand(command)
bjanakiraman7f4a4852013-02-15 04:35:28 +0000209
bjanakiraman7f4a4852013-02-15 04:35:28 +0000210
asharif0d3535a2013-02-15 04:50:33 +0000211def Main(argv):
George Burgess IV74bd3802022-09-02 16:59:27 -0700212 """The main function."""
213 # Common initializations
214 parser = argparse.ArgumentParser()
215 parser.add_argument(
216 "-c",
217 "--chromeos_root",
218 dest="chromeos_root",
219 default="../../",
220 help=("ChromeOS root checkout directory" " uses ../.. if none given."),
221 )
222 parser.add_argument(
223 "-g",
224 "--gcc_dir",
225 dest="gcc_dir",
226 help="The directory where gcc resides.",
227 )
228 parser.add_argument(
229 "--binutils_dir",
230 dest="binutils_dir",
231 help="The directory where binutils resides.",
232 )
233 parser.add_argument(
234 "-x",
235 "--gdb_dir",
236 dest="gdb_dir",
237 help="The directory where gdb resides.",
238 )
239 parser.add_argument(
240 "-b",
241 "--board",
242 dest="board",
243 default="x86-alex",
244 help="The target board.",
245 )
246 parser.add_argument(
247 "-n",
248 "--noincremental",
249 dest="noincremental",
250 default=False,
251 action="store_true",
252 help="Use FEATURES=keepwork to do incremental builds.",
253 )
254 parser.add_argument(
255 "--cflags",
256 dest="cflags",
257 default="",
258 help="Build a compiler with specified CFLAGS",
259 )
260 parser.add_argument(
261 "--cxxflags",
262 dest="cxxflags",
263 default="",
264 help="Build a compiler with specified CXXFLAGS",
265 )
266 parser.add_argument(
267 "--cflags_for_target",
268 dest="cflags_for_target",
269 default="",
270 help="Build the target libraries with specified flags",
271 )
272 parser.add_argument(
273 "--cxxflags_for_target",
274 dest="cxxflags_for_target",
275 default="",
276 help="Build the target libraries with specified flags",
277 )
278 parser.add_argument(
279 "--ldflags",
280 dest="ldflags",
281 default="",
282 help="Build a compiler with specified LDFLAGS",
283 )
284 parser.add_argument(
285 "-d",
286 "--debug",
287 dest="debug",
288 default=False,
289 action="store_true",
290 help="Build a compiler with -g3 -O0 appended to both"
291 " CFLAGS and CXXFLAGS.",
292 )
293 parser.add_argument(
294 "-m",
295 "--mount_only",
296 dest="mount_only",
297 default=False,
298 action="store_true",
299 help="Just mount the tool directories.",
300 )
301 parser.add_argument(
302 "-u",
303 "--unmount_only",
304 dest="unmount_only",
305 default=False,
306 action="store_true",
307 help="Just unmount the tool directories.",
308 )
309 parser.add_argument(
310 "--extra_use_flags",
311 dest="extra_use_flags",
312 default="",
313 help="Extra flag for USE, to be passed to the ebuild. "
314 "('multislot' and 'mounted_<tool>' are always passed.)",
315 )
316 parser.add_argument(
317 "--gcc_enable_ccache",
318 dest="gcc_enable_ccache",
319 default=False,
320 action="store_true",
321 help="Enable ccache for the gcc invocations",
322 )
bjanakiraman7f4a4852013-02-15 04:35:28 +0000323
George Burgess IV74bd3802022-09-02 16:59:27 -0700324 options = parser.parse_args(argv)
asharif17621302013-02-15 04:46:35 +0000325
George Burgess IV74bd3802022-09-02 16:59:27 -0700326 chromeos_root = misc.CanonicalizePath(options.chromeos_root)
asharif86968c42013-02-15 23:44:37 +0000327 if options.gcc_dir:
George Burgess IV74bd3802022-09-02 16:59:27 -0700328 gcc_dir = misc.CanonicalizePath(options.gcc_dir)
329 assert gcc_dir and os.path.isdir(gcc_dir), "gcc_dir does not exist!"
shenhan8e8b0c22013-02-19 22:34:16 +0000330 if options.binutils_dir:
George Burgess IV74bd3802022-09-02 16:59:27 -0700331 binutils_dir = misc.CanonicalizePath(options.binutils_dir)
332 assert os.path.isdir(binutils_dir), "binutils_dir does not exist!"
cmtice80d257f2013-02-15 23:44:51 +0000333 if options.gdb_dir:
George Burgess IV74bd3802022-09-02 16:59:27 -0700334 gdb_dir = misc.CanonicalizePath(options.gdb_dir)
335 assert os.path.isdir(gdb_dir), "gdb_dir does not exist!"
336 if options.unmount_only:
337 options.mount_only = False
338 elif options.mount_only:
339 options.unmount_only = False
340 build_env = {}
341 if options.cflags:
342 build_env["CFLAGS"] = "`portageq envvar CFLAGS` " + options.cflags
343 if options.cxxflags:
344 build_env["CXXFLAGS"] = "`portageq envvar CXXFLAGS` " + options.cxxflags
345 if options.cflags_for_target:
346 build_env["CFLAGS_FOR_TARGET"] = options.cflags_for_target
347 if options.cxxflags_for_target:
348 build_env["CXXFLAGS_FOR_TARGET"] = options.cxxflags_for_target
349 if options.ldflags:
350 build_env["LDFLAGS"] = options.ldflags
351 if options.debug:
352 debug_flags = "-g3 -O0"
353 if "CFLAGS" in build_env:
354 build_env["CFLAGS"] += " %s" % (debug_flags)
355 else:
356 build_env["CFLAGS"] = debug_flags
357 if "CXXFLAGS" in build_env:
358 build_env["CXXFLAGS"] += " %s" % (debug_flags)
359 else:
360 build_env["CXXFLAGS"] = debug_flags
361 if options.extra_use_flags:
362 build_env["USE"] = options.extra_use_flags
asharif86968c42013-02-15 23:44:37 +0000363
George Burgess IV74bd3802022-09-02 16:59:27 -0700364 # Create toolchain parts
365 toolchain_parts = {}
366 for board in options.board.split(","):
367 if options.gcc_dir:
368 tp = ToolchainPart(
369 "gcc",
370 gcc_dir,
371 chromeos_root,
372 board,
373 not options.noincremental,
374 build_env,
375 options.gcc_enable_ccache,
376 )
377 toolchain_parts[tp.tag] = tp
378 tp.RunSetupBoardIfNecessary()
379 if options.binutils_dir:
380 tp = ToolchainPart(
381 "binutils",
382 binutils_dir,
383 chromeos_root,
384 board,
385 not options.noincremental,
386 build_env,
387 )
388 toolchain_parts[tp.tag] = tp
389 tp.RunSetupBoardIfNecessary()
390 if options.gdb_dir:
391 tp = ToolchainPart(
392 "gdb",
393 gdb_dir,
394 chromeos_root,
395 board,
396 not options.noincremental,
397 build_env,
398 )
399 toolchain_parts[tp.tag] = tp
400 tp.RunSetupBoardIfNecessary()
401
402 rv = 0
403 try:
404 for tag in toolchain_parts:
405 tp = toolchain_parts[tag]
406 if options.mount_only or options.unmount_only:
407 tp.MountSources(options.unmount_only)
408 else:
409 rv = rv + tp.Build()
410 finally:
411 print("Exiting...")
412 return rv
asharif19c73dd2013-02-15 04:35:37 +0000413
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800414
George Burgess IV74bd3802022-09-02 16:59:27 -0700415if __name__ == "__main__":
416 retval = Main(sys.argv[1:])
417 sys.exit(retval)