1*760c253cSXin Li#!/usr/bin/env python3 2*760c253cSXin Li# -*- coding: utf-8 -*- 3*760c253cSXin Li# Copyright 2010 The ChromiumOS Authors 4*760c253cSXin Li# Use of this source code is governed by a BSD-style license that can be 5*760c253cSXin Li# found in the LICENSE file. 6*760c253cSXin Li 7*760c253cSXin Li"""Script to build the ChromeOS toolchain. 8*760c253cSXin Li 9*760c253cSXin LiThis script sets up the toolchain if you give it the gcctools directory. 10*760c253cSXin Li""" 11*760c253cSXin Li 12*760c253cSXin Li 13*760c253cSXin Li__author__ = "[email protected] (Ahmad Sharif)" 14*760c253cSXin Li 15*760c253cSXin Liimport argparse 16*760c253cSXin Liimport getpass 17*760c253cSXin Liimport os 18*760c253cSXin Liimport sys 19*760c253cSXin Liimport tempfile 20*760c253cSXin Li 21*760c253cSXin Lifrom cros_utils import command_executer 22*760c253cSXin Lifrom cros_utils import constants 23*760c253cSXin Lifrom cros_utils import misc 24*760c253cSXin Liimport tc_enter_chroot 25*760c253cSXin Li 26*760c253cSXin Li 27*760c253cSXin Liclass ToolchainPart(object): 28*760c253cSXin Li """Class to hold the toolchain pieces.""" 29*760c253cSXin Li 30*760c253cSXin Li def __init__( 31*760c253cSXin Li self, 32*760c253cSXin Li name, 33*760c253cSXin Li source_path, 34*760c253cSXin Li chromeos_root, 35*760c253cSXin Li board, 36*760c253cSXin Li incremental, 37*760c253cSXin Li build_env, 38*760c253cSXin Li gcc_enable_ccache=False, 39*760c253cSXin Li ): 40*760c253cSXin Li self._name = name 41*760c253cSXin Li self._source_path = misc.CanonicalizePath(source_path) 42*760c253cSXin Li self._chromeos_root = chromeos_root 43*760c253cSXin Li self._board = board 44*760c253cSXin Li self._ctarget = misc.GetCtargetFromBoard( 45*760c253cSXin Li self._board, self._chromeos_root 46*760c253cSXin Li ) 47*760c253cSXin Li self._gcc_libs_dest = misc.GetGccLibsDestForBoard( 48*760c253cSXin Li self._board, self._chromeos_root 49*760c253cSXin Li ) 50*760c253cSXin Li self.tag = "%s-%s" % (name, self._ctarget) 51*760c253cSXin Li self._ce = command_executer.GetCommandExecuter() 52*760c253cSXin Li self._mask_file = os.path.join( 53*760c253cSXin Li self._chromeos_root, 54*760c253cSXin Li "chroot", 55*760c253cSXin Li "etc/portage/package.mask/cross-%s" % self._ctarget, 56*760c253cSXin Li ) 57*760c253cSXin Li self._new_mask_file = None 58*760c253cSXin Li 59*760c253cSXin Li self._chroot_source_path = os.path.join( 60*760c253cSXin Li constants.MOUNTED_TOOLCHAIN_ROOT, self._name 61*760c253cSXin Li ).lstrip("/") 62*760c253cSXin Li self._incremental = incremental 63*760c253cSXin Li self._build_env = build_env 64*760c253cSXin Li self._gcc_enable_ccache = gcc_enable_ccache 65*760c253cSXin Li 66*760c253cSXin Li def RunSetupBoardIfNecessary(self): 67*760c253cSXin Li cross_symlink = os.path.join( 68*760c253cSXin Li self._chromeos_root, 69*760c253cSXin Li "chroot", 70*760c253cSXin Li "usr/local/bin/emerge-%s" % self._board, 71*760c253cSXin Li ) 72*760c253cSXin Li if not os.path.exists(cross_symlink): 73*760c253cSXin Li command = "setup_board --board=%s" % self._board 74*760c253cSXin Li self._ce.ChrootRunCommand(self._chromeos_root, command) 75*760c253cSXin Li 76*760c253cSXin Li def Build(self): 77*760c253cSXin Li rv = 1 78*760c253cSXin Li try: 79*760c253cSXin Li self.UninstallTool() 80*760c253cSXin Li self.MoveMaskFile() 81*760c253cSXin Li self.MountSources(False) 82*760c253cSXin Li self.RemoveCompiledFile() 83*760c253cSXin Li rv = self.BuildTool() 84*760c253cSXin Li finally: 85*760c253cSXin Li self.UnMoveMaskFile() 86*760c253cSXin Li return rv 87*760c253cSXin Li 88*760c253cSXin Li def RemoveCompiledFile(self): 89*760c253cSXin Li compiled_file = os.path.join( 90*760c253cSXin Li self._chromeos_root, 91*760c253cSXin Li "chroot", 92*760c253cSXin Li "var/tmp/portage/cross-%s" % self._ctarget, 93*760c253cSXin Li "%s-9999" % self._name, 94*760c253cSXin Li ".compiled", 95*760c253cSXin Li ) 96*760c253cSXin Li command = "rm -f %s" % compiled_file 97*760c253cSXin Li self._ce.RunCommand(command) 98*760c253cSXin Li 99*760c253cSXin Li def MountSources(self, unmount_source): 100*760c253cSXin Li mount_points = [] 101*760c253cSXin Li mounted_source_path = os.path.join( 102*760c253cSXin Li self._chromeos_root, "chroot", self._chroot_source_path 103*760c253cSXin Li ) 104*760c253cSXin Li src_mp = tc_enter_chroot.MountPoint( 105*760c253cSXin Li self._source_path, mounted_source_path, getpass.getuser(), "ro" 106*760c253cSXin Li ) 107*760c253cSXin Li mount_points.append(src_mp) 108*760c253cSXin Li 109*760c253cSXin Li build_suffix = "build-%s" % self._ctarget 110*760c253cSXin Li build_dir = "%s-%s" % (self._source_path, build_suffix) 111*760c253cSXin Li 112*760c253cSXin Li if not self._incremental and os.path.exists(build_dir): 113*760c253cSXin Li command = "rm -rf %s/*" % build_dir 114*760c253cSXin Li self._ce.RunCommand(command) 115*760c253cSXin Li 116*760c253cSXin Li # Create a -build directory for the objects. 117*760c253cSXin Li command = "mkdir -p %s" % build_dir 118*760c253cSXin Li self._ce.RunCommand(command) 119*760c253cSXin Li 120*760c253cSXin Li mounted_build_dir = os.path.join( 121*760c253cSXin Li self._chromeos_root, 122*760c253cSXin Li "chroot", 123*760c253cSXin Li "%s-%s" % (self._chroot_source_path, build_suffix), 124*760c253cSXin Li ) 125*760c253cSXin Li build_mp = tc_enter_chroot.MountPoint( 126*760c253cSXin Li build_dir, mounted_build_dir, getpass.getuser() 127*760c253cSXin Li ) 128*760c253cSXin Li mount_points.append(build_mp) 129*760c253cSXin Li 130*760c253cSXin Li if unmount_source: 131*760c253cSXin Li unmount_statuses = [mp.UnMount() == 0 for mp in mount_points] 132*760c253cSXin Li assert all(unmount_statuses), "Could not unmount all mount points!" 133*760c253cSXin Li else: 134*760c253cSXin Li mount_statuses = [mp.DoMount() == 0 for mp in mount_points] 135*760c253cSXin Li 136*760c253cSXin Li if not all(mount_statuses): 137*760c253cSXin Li mounted = [ 138*760c253cSXin Li mp 139*760c253cSXin Li for mp, status in zip(mount_points, mount_statuses) 140*760c253cSXin Li if status 141*760c253cSXin Li ] 142*760c253cSXin Li unmount_statuses = [mp.UnMount() == 0 for mp in mounted] 143*760c253cSXin Li assert all( 144*760c253cSXin Li unmount_statuses 145*760c253cSXin Li ), "Could not unmount all mount points!" 146*760c253cSXin Li 147*760c253cSXin Li def UninstallTool(self): 148*760c253cSXin Li command = "sudo CLEAN_DELAY=0 emerge -C cross-%s/%s" % ( 149*760c253cSXin Li self._ctarget, 150*760c253cSXin Li self._name, 151*760c253cSXin Li ) 152*760c253cSXin Li self._ce.ChrootRunCommand(self._chromeos_root, command) 153*760c253cSXin Li 154*760c253cSXin Li def BuildTool(self): 155*760c253cSXin Li env = self._build_env 156*760c253cSXin Li # FEATURES=buildpkg adds minutes of time so we disable it. 157*760c253cSXin Li # TODO(shenhan): keep '-sandbox' for a while for compatibility, then remove 158*760c253cSXin Li # it after a while. 159*760c253cSXin Li features = ( 160*760c253cSXin Li "nostrip userpriv userfetch -usersandbox -sandbox noclean " 161*760c253cSXin Li "-buildpkg" 162*760c253cSXin Li ) 163*760c253cSXin Li env["FEATURES"] = features 164*760c253cSXin Li 165*760c253cSXin Li if self._incremental: 166*760c253cSXin Li env["FEATURES"] += " keepwork" 167*760c253cSXin Li 168*760c253cSXin Li if "USE" in env: 169*760c253cSXin Li env["USE"] += " multislot mounted_%s" % self._name 170*760c253cSXin Li else: 171*760c253cSXin Li env["USE"] = "multislot mounted_%s" % self._name 172*760c253cSXin Li 173*760c253cSXin Li # Disable ccache in our compilers. cache may be problematic for us. 174*760c253cSXin Li # It ignores compiler environments settings and it is not clear if 175*760c253cSXin Li # the cache hit algorithm verifies all the compiler binaries or 176*760c253cSXin Li # just the driver. 177*760c253cSXin Li if self._name == "gcc" and not self._gcc_enable_ccache: 178*760c253cSXin Li env["USE"] += " -wrapper_ccache" 179*760c253cSXin Li 180*760c253cSXin Li env["%s_SOURCE_PATH" % self._name.upper()] = os.path.join( 181*760c253cSXin Li "/", self._chroot_source_path 182*760c253cSXin Li ) 183*760c253cSXin Li env["ACCEPT_KEYWORDS"] = "~*" 184*760c253cSXin Li env_string = " ".join(['%s="%s"' % var for var in env.items()]) 185*760c253cSXin Li command = "emerge =cross-%s/%s-9999" % (self._ctarget, self._name) 186*760c253cSXin Li full_command = "sudo %s %s" % (env_string, command) 187*760c253cSXin Li rv = self._ce.ChrootRunCommand(self._chromeos_root, full_command) 188*760c253cSXin Li if rv != 0: 189*760c253cSXin Li return rv 190*760c253cSXin Li if self._name == "gcc": 191*760c253cSXin Li command = "sudo cp -r /usr/lib/gcc/%s %s" % ( 192*760c253cSXin Li self._ctarget, 193*760c253cSXin Li self._gcc_libs_dest, 194*760c253cSXin Li ) 195*760c253cSXin Li rv = self._ce.ChrootRunCommand(self._chromeos_root, command) 196*760c253cSXin Li return rv 197*760c253cSXin Li 198*760c253cSXin Li def MoveMaskFile(self): 199*760c253cSXin Li self._new_mask_file = None 200*760c253cSXin Li if os.path.isfile(self._mask_file): 201*760c253cSXin Li self._new_mask_file = tempfile.mktemp() 202*760c253cSXin Li command = "sudo mv %s %s" % (self._mask_file, self._new_mask_file) 203*760c253cSXin Li self._ce.RunCommand(command) 204*760c253cSXin Li 205*760c253cSXin Li def UnMoveMaskFile(self): 206*760c253cSXin Li if self._new_mask_file: 207*760c253cSXin Li command = "sudo mv %s %s" % (self._new_mask_file, self._mask_file) 208*760c253cSXin Li self._ce.RunCommand(command) 209*760c253cSXin Li 210*760c253cSXin Li 211*760c253cSXin Lidef Main(argv): 212*760c253cSXin Li """The main function.""" 213*760c253cSXin Li # Common initializations 214*760c253cSXin Li parser = argparse.ArgumentParser() 215*760c253cSXin Li parser.add_argument( 216*760c253cSXin Li "-c", 217*760c253cSXin Li "--chromeos_root", 218*760c253cSXin Li dest="chromeos_root", 219*760c253cSXin Li default="../../", 220*760c253cSXin Li help=("ChromeOS root checkout directory" " uses ../.. if none given."), 221*760c253cSXin Li ) 222*760c253cSXin Li parser.add_argument( 223*760c253cSXin Li "-g", 224*760c253cSXin Li "--gcc_dir", 225*760c253cSXin Li dest="gcc_dir", 226*760c253cSXin Li help="The directory where gcc resides.", 227*760c253cSXin Li ) 228*760c253cSXin Li parser.add_argument( 229*760c253cSXin Li "--binutils_dir", 230*760c253cSXin Li dest="binutils_dir", 231*760c253cSXin Li help="The directory where binutils resides.", 232*760c253cSXin Li ) 233*760c253cSXin Li parser.add_argument( 234*760c253cSXin Li "-x", 235*760c253cSXin Li "--gdb_dir", 236*760c253cSXin Li dest="gdb_dir", 237*760c253cSXin Li help="The directory where gdb resides.", 238*760c253cSXin Li ) 239*760c253cSXin Li parser.add_argument( 240*760c253cSXin Li "-b", 241*760c253cSXin Li "--board", 242*760c253cSXin Li dest="board", 243*760c253cSXin Li default="x86-alex", 244*760c253cSXin Li help="The target board.", 245*760c253cSXin Li ) 246*760c253cSXin Li parser.add_argument( 247*760c253cSXin Li "-n", 248*760c253cSXin Li "--noincremental", 249*760c253cSXin Li dest="noincremental", 250*760c253cSXin Li default=False, 251*760c253cSXin Li action="store_true", 252*760c253cSXin Li help="Use FEATURES=keepwork to do incremental builds.", 253*760c253cSXin Li ) 254*760c253cSXin Li parser.add_argument( 255*760c253cSXin Li "--cflags", 256*760c253cSXin Li dest="cflags", 257*760c253cSXin Li default="", 258*760c253cSXin Li help="Build a compiler with specified CFLAGS", 259*760c253cSXin Li ) 260*760c253cSXin Li parser.add_argument( 261*760c253cSXin Li "--cxxflags", 262*760c253cSXin Li dest="cxxflags", 263*760c253cSXin Li default="", 264*760c253cSXin Li help="Build a compiler with specified CXXFLAGS", 265*760c253cSXin Li ) 266*760c253cSXin Li parser.add_argument( 267*760c253cSXin Li "--cflags_for_target", 268*760c253cSXin Li dest="cflags_for_target", 269*760c253cSXin Li default="", 270*760c253cSXin Li help="Build the target libraries with specified flags", 271*760c253cSXin Li ) 272*760c253cSXin Li parser.add_argument( 273*760c253cSXin Li "--cxxflags_for_target", 274*760c253cSXin Li dest="cxxflags_for_target", 275*760c253cSXin Li default="", 276*760c253cSXin Li help="Build the target libraries with specified flags", 277*760c253cSXin Li ) 278*760c253cSXin Li parser.add_argument( 279*760c253cSXin Li "--ldflags", 280*760c253cSXin Li dest="ldflags", 281*760c253cSXin Li default="", 282*760c253cSXin Li help="Build a compiler with specified LDFLAGS", 283*760c253cSXin Li ) 284*760c253cSXin Li parser.add_argument( 285*760c253cSXin Li "-d", 286*760c253cSXin Li "--debug", 287*760c253cSXin Li dest="debug", 288*760c253cSXin Li default=False, 289*760c253cSXin Li action="store_true", 290*760c253cSXin Li help="Build a compiler with -g3 -O0 appended to both" 291*760c253cSXin Li " CFLAGS and CXXFLAGS.", 292*760c253cSXin Li ) 293*760c253cSXin Li parser.add_argument( 294*760c253cSXin Li "-m", 295*760c253cSXin Li "--mount_only", 296*760c253cSXin Li dest="mount_only", 297*760c253cSXin Li default=False, 298*760c253cSXin Li action="store_true", 299*760c253cSXin Li help="Just mount the tool directories.", 300*760c253cSXin Li ) 301*760c253cSXin Li parser.add_argument( 302*760c253cSXin Li "-u", 303*760c253cSXin Li "--unmount_only", 304*760c253cSXin Li dest="unmount_only", 305*760c253cSXin Li default=False, 306*760c253cSXin Li action="store_true", 307*760c253cSXin Li help="Just unmount the tool directories.", 308*760c253cSXin Li ) 309*760c253cSXin Li parser.add_argument( 310*760c253cSXin Li "--extra_use_flags", 311*760c253cSXin Li dest="extra_use_flags", 312*760c253cSXin Li default="", 313*760c253cSXin Li help="Extra flag for USE, to be passed to the ebuild. " 314*760c253cSXin Li "('multislot' and 'mounted_<tool>' are always passed.)", 315*760c253cSXin Li ) 316*760c253cSXin Li parser.add_argument( 317*760c253cSXin Li "--gcc_enable_ccache", 318*760c253cSXin Li dest="gcc_enable_ccache", 319*760c253cSXin Li default=False, 320*760c253cSXin Li action="store_true", 321*760c253cSXin Li help="Enable ccache for the gcc invocations", 322*760c253cSXin Li ) 323*760c253cSXin Li 324*760c253cSXin Li options = parser.parse_args(argv) 325*760c253cSXin Li 326*760c253cSXin Li chromeos_root = misc.CanonicalizePath(options.chromeos_root) 327*760c253cSXin Li if options.gcc_dir: 328*760c253cSXin Li gcc_dir = misc.CanonicalizePath(options.gcc_dir) 329*760c253cSXin Li assert gcc_dir and os.path.isdir(gcc_dir), "gcc_dir does not exist!" 330*760c253cSXin Li if options.binutils_dir: 331*760c253cSXin Li binutils_dir = misc.CanonicalizePath(options.binutils_dir) 332*760c253cSXin Li assert os.path.isdir(binutils_dir), "binutils_dir does not exist!" 333*760c253cSXin Li if options.gdb_dir: 334*760c253cSXin Li gdb_dir = misc.CanonicalizePath(options.gdb_dir) 335*760c253cSXin Li assert os.path.isdir(gdb_dir), "gdb_dir does not exist!" 336*760c253cSXin Li if options.unmount_only: 337*760c253cSXin Li options.mount_only = False 338*760c253cSXin Li elif options.mount_only: 339*760c253cSXin Li options.unmount_only = False 340*760c253cSXin Li build_env = {} 341*760c253cSXin Li if options.cflags: 342*760c253cSXin Li build_env["CFLAGS"] = "`portageq envvar CFLAGS` " + options.cflags 343*760c253cSXin Li if options.cxxflags: 344*760c253cSXin Li build_env["CXXFLAGS"] = "`portageq envvar CXXFLAGS` " + options.cxxflags 345*760c253cSXin Li if options.cflags_for_target: 346*760c253cSXin Li build_env["CFLAGS_FOR_TARGET"] = options.cflags_for_target 347*760c253cSXin Li if options.cxxflags_for_target: 348*760c253cSXin Li build_env["CXXFLAGS_FOR_TARGET"] = options.cxxflags_for_target 349*760c253cSXin Li if options.ldflags: 350*760c253cSXin Li build_env["LDFLAGS"] = options.ldflags 351*760c253cSXin Li if options.debug: 352*760c253cSXin Li debug_flags = "-g3 -O0" 353*760c253cSXin Li if "CFLAGS" in build_env: 354*760c253cSXin Li build_env["CFLAGS"] += " %s" % (debug_flags) 355*760c253cSXin Li else: 356*760c253cSXin Li build_env["CFLAGS"] = debug_flags 357*760c253cSXin Li if "CXXFLAGS" in build_env: 358*760c253cSXin Li build_env["CXXFLAGS"] += " %s" % (debug_flags) 359*760c253cSXin Li else: 360*760c253cSXin Li build_env["CXXFLAGS"] = debug_flags 361*760c253cSXin Li if options.extra_use_flags: 362*760c253cSXin Li build_env["USE"] = options.extra_use_flags 363*760c253cSXin Li 364*760c253cSXin Li # Create toolchain parts 365*760c253cSXin Li toolchain_parts = {} 366*760c253cSXin Li for board in options.board.split(","): 367*760c253cSXin Li if options.gcc_dir: 368*760c253cSXin Li tp = ToolchainPart( 369*760c253cSXin Li "gcc", 370*760c253cSXin Li gcc_dir, 371*760c253cSXin Li chromeos_root, 372*760c253cSXin Li board, 373*760c253cSXin Li not options.noincremental, 374*760c253cSXin Li build_env, 375*760c253cSXin Li options.gcc_enable_ccache, 376*760c253cSXin Li ) 377*760c253cSXin Li toolchain_parts[tp.tag] = tp 378*760c253cSXin Li tp.RunSetupBoardIfNecessary() 379*760c253cSXin Li if options.binutils_dir: 380*760c253cSXin Li tp = ToolchainPart( 381*760c253cSXin Li "binutils", 382*760c253cSXin Li binutils_dir, 383*760c253cSXin Li chromeos_root, 384*760c253cSXin Li board, 385*760c253cSXin Li not options.noincremental, 386*760c253cSXin Li build_env, 387*760c253cSXin Li ) 388*760c253cSXin Li toolchain_parts[tp.tag] = tp 389*760c253cSXin Li tp.RunSetupBoardIfNecessary() 390*760c253cSXin Li if options.gdb_dir: 391*760c253cSXin Li tp = ToolchainPart( 392*760c253cSXin Li "gdb", 393*760c253cSXin Li gdb_dir, 394*760c253cSXin Li chromeos_root, 395*760c253cSXin Li board, 396*760c253cSXin Li not options.noincremental, 397*760c253cSXin Li build_env, 398*760c253cSXin Li ) 399*760c253cSXin Li toolchain_parts[tp.tag] = tp 400*760c253cSXin Li tp.RunSetupBoardIfNecessary() 401*760c253cSXin Li 402*760c253cSXin Li rv = 0 403*760c253cSXin Li try: 404*760c253cSXin Li for tag in toolchain_parts: 405*760c253cSXin Li tp = toolchain_parts[tag] 406*760c253cSXin Li if options.mount_only or options.unmount_only: 407*760c253cSXin Li tp.MountSources(options.unmount_only) 408*760c253cSXin Li else: 409*760c253cSXin Li rv = rv + tp.Build() 410*760c253cSXin Li finally: 411*760c253cSXin Li print("Exiting...") 412*760c253cSXin Li return rv 413*760c253cSXin Li 414*760c253cSXin Li 415*760c253cSXin Liif __name__ == "__main__": 416*760c253cSXin Li retval = Main(sys.argv[1:]) 417*760c253cSXin Li sys.exit(retval) 418