You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
418 lines
13 KiB
418 lines
13 KiB
#!/usr/bin/env python3
|
|
# -*- coding: utf-8 -*-
|
|
# Copyright 2010 The ChromiumOS Authors
|
|
# Use of this source code is governed by a BSD-style license that can be
|
|
# found in the LICENSE file.
|
|
|
|
"""Script to build the ChromeOS toolchain.
|
|
|
|
This script sets up the toolchain if you give it the gcctools directory.
|
|
"""
|
|
|
|
|
|
__author__ = "asharif@google.com (Ahmad Sharif)"
|
|
|
|
import argparse
|
|
import getpass
|
|
import os
|
|
import sys
|
|
import tempfile
|
|
|
|
from cros_utils import command_executer
|
|
from cros_utils import constants
|
|
from cros_utils import misc
|
|
import tc_enter_chroot
|
|
|
|
|
|
class ToolchainPart(object):
|
|
"""Class to hold the toolchain pieces."""
|
|
|
|
def __init__(
|
|
self,
|
|
name,
|
|
source_path,
|
|
chromeos_root,
|
|
board,
|
|
incremental,
|
|
build_env,
|
|
gcc_enable_ccache=False,
|
|
):
|
|
self._name = name
|
|
self._source_path = misc.CanonicalizePath(source_path)
|
|
self._chromeos_root = chromeos_root
|
|
self._board = board
|
|
self._ctarget = misc.GetCtargetFromBoard(
|
|
self._board, self._chromeos_root
|
|
)
|
|
self._gcc_libs_dest = misc.GetGccLibsDestForBoard(
|
|
self._board, self._chromeos_root
|
|
)
|
|
self.tag = "%s-%s" % (name, self._ctarget)
|
|
self._ce = command_executer.GetCommandExecuter()
|
|
self._mask_file = os.path.join(
|
|
self._chromeos_root,
|
|
"chroot",
|
|
"etc/portage/package.mask/cross-%s" % self._ctarget,
|
|
)
|
|
self._new_mask_file = None
|
|
|
|
self._chroot_source_path = os.path.join(
|
|
constants.MOUNTED_TOOLCHAIN_ROOT, self._name
|
|
).lstrip("/")
|
|
self._incremental = incremental
|
|
self._build_env = build_env
|
|
self._gcc_enable_ccache = gcc_enable_ccache
|
|
|
|
def RunSetupBoardIfNecessary(self):
|
|
cross_symlink = os.path.join(
|
|
self._chromeos_root,
|
|
"chroot",
|
|
"usr/local/bin/emerge-%s" % self._board,
|
|
)
|
|
if not os.path.exists(cross_symlink):
|
|
command = "setup_board --board=%s" % self._board
|
|
self._ce.ChrootRunCommand(self._chromeos_root, command)
|
|
|
|
def Build(self):
|
|
rv = 1
|
|
try:
|
|
self.UninstallTool()
|
|
self.MoveMaskFile()
|
|
self.MountSources(False)
|
|
self.RemoveCompiledFile()
|
|
rv = self.BuildTool()
|
|
finally:
|
|
self.UnMoveMaskFile()
|
|
return rv
|
|
|
|
def RemoveCompiledFile(self):
|
|
compiled_file = os.path.join(
|
|
self._chromeos_root,
|
|
"chroot",
|
|
"var/tmp/portage/cross-%s" % self._ctarget,
|
|
"%s-9999" % self._name,
|
|
".compiled",
|
|
)
|
|
command = "rm -f %s" % compiled_file
|
|
self._ce.RunCommand(command)
|
|
|
|
def MountSources(self, unmount_source):
|
|
mount_points = []
|
|
mounted_source_path = os.path.join(
|
|
self._chromeos_root, "chroot", self._chroot_source_path
|
|
)
|
|
src_mp = tc_enter_chroot.MountPoint(
|
|
self._source_path, mounted_source_path, getpass.getuser(), "ro"
|
|
)
|
|
mount_points.append(src_mp)
|
|
|
|
build_suffix = "build-%s" % self._ctarget
|
|
build_dir = "%s-%s" % (self._source_path, build_suffix)
|
|
|
|
if not self._incremental and os.path.exists(build_dir):
|
|
command = "rm -rf %s/*" % build_dir
|
|
self._ce.RunCommand(command)
|
|
|
|
# Create a -build directory for the objects.
|
|
command = "mkdir -p %s" % build_dir
|
|
self._ce.RunCommand(command)
|
|
|
|
mounted_build_dir = os.path.join(
|
|
self._chromeos_root,
|
|
"chroot",
|
|
"%s-%s" % (self._chroot_source_path, build_suffix),
|
|
)
|
|
build_mp = tc_enter_chroot.MountPoint(
|
|
build_dir, mounted_build_dir, getpass.getuser()
|
|
)
|
|
mount_points.append(build_mp)
|
|
|
|
if unmount_source:
|
|
unmount_statuses = [mp.UnMount() == 0 for mp in mount_points]
|
|
assert all(unmount_statuses), "Could not unmount all mount points!"
|
|
else:
|
|
mount_statuses = [mp.DoMount() == 0 for mp in mount_points]
|
|
|
|
if not all(mount_statuses):
|
|
mounted = [
|
|
mp
|
|
for mp, status in zip(mount_points, mount_statuses)
|
|
if status
|
|
]
|
|
unmount_statuses = [mp.UnMount() == 0 for mp in mounted]
|
|
assert all(
|
|
unmount_statuses
|
|
), "Could not unmount all mount points!"
|
|
|
|
def UninstallTool(self):
|
|
command = "sudo CLEAN_DELAY=0 emerge -C cross-%s/%s" % (
|
|
self._ctarget,
|
|
self._name,
|
|
)
|
|
self._ce.ChrootRunCommand(self._chromeos_root, command)
|
|
|
|
def BuildTool(self):
|
|
env = self._build_env
|
|
# FEATURES=buildpkg adds minutes of time so we disable it.
|
|
# TODO(shenhan): keep '-sandbox' for a while for compatibility, then remove
|
|
# it after a while.
|
|
features = (
|
|
"nostrip userpriv userfetch -usersandbox -sandbox noclean "
|
|
"-buildpkg"
|
|
)
|
|
env["FEATURES"] = features
|
|
|
|
if self._incremental:
|
|
env["FEATURES"] += " keepwork"
|
|
|
|
if "USE" in env:
|
|
env["USE"] += " multislot mounted_%s" % self._name
|
|
else:
|
|
env["USE"] = "multislot mounted_%s" % self._name
|
|
|
|
# Disable ccache in our compilers. cache may be problematic for us.
|
|
# It ignores compiler environments settings and it is not clear if
|
|
# the cache hit algorithm verifies all the compiler binaries or
|
|
# just the driver.
|
|
if self._name == "gcc" and not self._gcc_enable_ccache:
|
|
env["USE"] += " -wrapper_ccache"
|
|
|
|
env["%s_SOURCE_PATH" % self._name.upper()] = os.path.join(
|
|
"/", self._chroot_source_path
|
|
)
|
|
env["ACCEPT_KEYWORDS"] = "~*"
|
|
env_string = " ".join(['%s="%s"' % var for var in env.items()])
|
|
command = "emerge =cross-%s/%s-9999" % (self._ctarget, self._name)
|
|
full_command = "sudo %s %s" % (env_string, command)
|
|
rv = self._ce.ChrootRunCommand(self._chromeos_root, full_command)
|
|
if rv != 0:
|
|
return rv
|
|
if self._name == "gcc":
|
|
command = "sudo cp -r /usr/lib/gcc/%s %s" % (
|
|
self._ctarget,
|
|
self._gcc_libs_dest,
|
|
)
|
|
rv = self._ce.ChrootRunCommand(self._chromeos_root, command)
|
|
return rv
|
|
|
|
def MoveMaskFile(self):
|
|
self._new_mask_file = None
|
|
if os.path.isfile(self._mask_file):
|
|
self._new_mask_file = tempfile.mktemp()
|
|
command = "sudo mv %s %s" % (self._mask_file, self._new_mask_file)
|
|
self._ce.RunCommand(command)
|
|
|
|
def UnMoveMaskFile(self):
|
|
if self._new_mask_file:
|
|
command = "sudo mv %s %s" % (self._new_mask_file, self._mask_file)
|
|
self._ce.RunCommand(command)
|
|
|
|
|
|
def Main(argv):
|
|
"""The main function."""
|
|
# Common initializations
|
|
parser = argparse.ArgumentParser()
|
|
parser.add_argument(
|
|
"-c",
|
|
"--chromeos_root",
|
|
dest="chromeos_root",
|
|
default="../../",
|
|
help=("ChromeOS root checkout directory" " uses ../.. if none given."),
|
|
)
|
|
parser.add_argument(
|
|
"-g",
|
|
"--gcc_dir",
|
|
dest="gcc_dir",
|
|
help="The directory where gcc resides.",
|
|
)
|
|
parser.add_argument(
|
|
"--binutils_dir",
|
|
dest="binutils_dir",
|
|
help="The directory where binutils resides.",
|
|
)
|
|
parser.add_argument(
|
|
"-x",
|
|
"--gdb_dir",
|
|
dest="gdb_dir",
|
|
help="The directory where gdb resides.",
|
|
)
|
|
parser.add_argument(
|
|
"-b",
|
|
"--board",
|
|
dest="board",
|
|
default="x86-alex",
|
|
help="The target board.",
|
|
)
|
|
parser.add_argument(
|
|
"-n",
|
|
"--noincremental",
|
|
dest="noincremental",
|
|
default=False,
|
|
action="store_true",
|
|
help="Use FEATURES=keepwork to do incremental builds.",
|
|
)
|
|
parser.add_argument(
|
|
"--cflags",
|
|
dest="cflags",
|
|
default="",
|
|
help="Build a compiler with specified CFLAGS",
|
|
)
|
|
parser.add_argument(
|
|
"--cxxflags",
|
|
dest="cxxflags",
|
|
default="",
|
|
help="Build a compiler with specified CXXFLAGS",
|
|
)
|
|
parser.add_argument(
|
|
"--cflags_for_target",
|
|
dest="cflags_for_target",
|
|
default="",
|
|
help="Build the target libraries with specified flags",
|
|
)
|
|
parser.add_argument(
|
|
"--cxxflags_for_target",
|
|
dest="cxxflags_for_target",
|
|
default="",
|
|
help="Build the target libraries with specified flags",
|
|
)
|
|
parser.add_argument(
|
|
"--ldflags",
|
|
dest="ldflags",
|
|
default="",
|
|
help="Build a compiler with specified LDFLAGS",
|
|
)
|
|
parser.add_argument(
|
|
"-d",
|
|
"--debug",
|
|
dest="debug",
|
|
default=False,
|
|
action="store_true",
|
|
help="Build a compiler with -g3 -O0 appended to both"
|
|
" CFLAGS and CXXFLAGS.",
|
|
)
|
|
parser.add_argument(
|
|
"-m",
|
|
"--mount_only",
|
|
dest="mount_only",
|
|
default=False,
|
|
action="store_true",
|
|
help="Just mount the tool directories.",
|
|
)
|
|
parser.add_argument(
|
|
"-u",
|
|
"--unmount_only",
|
|
dest="unmount_only",
|
|
default=False,
|
|
action="store_true",
|
|
help="Just unmount the tool directories.",
|
|
)
|
|
parser.add_argument(
|
|
"--extra_use_flags",
|
|
dest="extra_use_flags",
|
|
default="",
|
|
help="Extra flag for USE, to be passed to the ebuild. "
|
|
"('multislot' and 'mounted_<tool>' are always passed.)",
|
|
)
|
|
parser.add_argument(
|
|
"--gcc_enable_ccache",
|
|
dest="gcc_enable_ccache",
|
|
default=False,
|
|
action="store_true",
|
|
help="Enable ccache for the gcc invocations",
|
|
)
|
|
|
|
options = parser.parse_args(argv)
|
|
|
|
chromeos_root = misc.CanonicalizePath(options.chromeos_root)
|
|
if options.gcc_dir:
|
|
gcc_dir = misc.CanonicalizePath(options.gcc_dir)
|
|
assert gcc_dir and os.path.isdir(gcc_dir), "gcc_dir does not exist!"
|
|
if options.binutils_dir:
|
|
binutils_dir = misc.CanonicalizePath(options.binutils_dir)
|
|
assert os.path.isdir(binutils_dir), "binutils_dir does not exist!"
|
|
if options.gdb_dir:
|
|
gdb_dir = misc.CanonicalizePath(options.gdb_dir)
|
|
assert os.path.isdir(gdb_dir), "gdb_dir does not exist!"
|
|
if options.unmount_only:
|
|
options.mount_only = False
|
|
elif options.mount_only:
|
|
options.unmount_only = False
|
|
build_env = {}
|
|
if options.cflags:
|
|
build_env["CFLAGS"] = "`portageq envvar CFLAGS` " + options.cflags
|
|
if options.cxxflags:
|
|
build_env["CXXFLAGS"] = "`portageq envvar CXXFLAGS` " + options.cxxflags
|
|
if options.cflags_for_target:
|
|
build_env["CFLAGS_FOR_TARGET"] = options.cflags_for_target
|
|
if options.cxxflags_for_target:
|
|
build_env["CXXFLAGS_FOR_TARGET"] = options.cxxflags_for_target
|
|
if options.ldflags:
|
|
build_env["LDFLAGS"] = options.ldflags
|
|
if options.debug:
|
|
debug_flags = "-g3 -O0"
|
|
if "CFLAGS" in build_env:
|
|
build_env["CFLAGS"] += " %s" % (debug_flags)
|
|
else:
|
|
build_env["CFLAGS"] = debug_flags
|
|
if "CXXFLAGS" in build_env:
|
|
build_env["CXXFLAGS"] += " %s" % (debug_flags)
|
|
else:
|
|
build_env["CXXFLAGS"] = debug_flags
|
|
if options.extra_use_flags:
|
|
build_env["USE"] = options.extra_use_flags
|
|
|
|
# Create toolchain parts
|
|
toolchain_parts = {}
|
|
for board in options.board.split(","):
|
|
if options.gcc_dir:
|
|
tp = ToolchainPart(
|
|
"gcc",
|
|
gcc_dir,
|
|
chromeos_root,
|
|
board,
|
|
not options.noincremental,
|
|
build_env,
|
|
options.gcc_enable_ccache,
|
|
)
|
|
toolchain_parts[tp.tag] = tp
|
|
tp.RunSetupBoardIfNecessary()
|
|
if options.binutils_dir:
|
|
tp = ToolchainPart(
|
|
"binutils",
|
|
binutils_dir,
|
|
chromeos_root,
|
|
board,
|
|
not options.noincremental,
|
|
build_env,
|
|
)
|
|
toolchain_parts[tp.tag] = tp
|
|
tp.RunSetupBoardIfNecessary()
|
|
if options.gdb_dir:
|
|
tp = ToolchainPart(
|
|
"gdb",
|
|
gdb_dir,
|
|
chromeos_root,
|
|
board,
|
|
not options.noincremental,
|
|
build_env,
|
|
)
|
|
toolchain_parts[tp.tag] = tp
|
|
tp.RunSetupBoardIfNecessary()
|
|
|
|
rv = 0
|
|
try:
|
|
for tag in toolchain_parts:
|
|
tp = toolchain_parts[tag]
|
|
if options.mount_only or options.unmount_only:
|
|
tp.MountSources(options.unmount_only)
|
|
else:
|
|
rv = rv + tp.Build()
|
|
finally:
|
|
print("Exiting...")
|
|
return rv
|
|
|
|
|
|
if __name__ == "__main__":
|
|
retval = Main(sys.argv[1:])
|
|
sys.exit(retval)
|