blob: 7a66a4da074ae09eda8f5c0106652c795e8e2982 [file] [log] [blame]
# -*- coding: utf-8 -*-
# Copyright 2015 The Chromium OS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""A type used to represent a toolchain and its setting overrides."""
from __future__ import print_function
import copy
import collections
import json
import os
import sys
from chromite.lib import osutils
assert sys.version_info >= (3, 6), 'This module requires Python 3.6+'
_ToolchainTuple = collections.namedtuple('_ToolchainTuple',
('target', 'setting_overrides'))
class MismatchedToolchainConfigsError(Exception):
"""We have no defined resolution for conflicting toolchain configs."""
class ToolchainList(object):
"""Represents a list of toolchains."""
def __init__(self, overlays):
"""Construct an instance.
overlays: list of overlay directories to add toolchains from.
if overlays is None:
raise ValueError('Must specify overlays.')
self._toolchains = []
self._auto_default_toolchain = None
for overlay_path in overlays:
def _AddToolchainsFromOverlayDir(self, overlay_dir):
"""Add toolchains to |self| from the given overlay.
Does not include overlays that this overlay depends on.
overlay_dir: absolute path to an overlay directory.
config_path = os.path.join(overlay_dir, 'toolchain.conf')
if not os.path.exists(config_path):
# Not all overlays define toolchains.
first_target = True
default_target = None
config_lines = osutils.ReadFile(config_path).splitlines()
for line in config_lines:
# Split by hash sign so that comments are ignored.
# Then split the line to get the tuple and its options.
line_pieces = line.split('#', 1)[0].split(None, 1)
if not line_pieces:
target = line_pieces[0]
settings = json.loads(line_pieces[1]) if len(line_pieces) > 1 else {}
if first_target:
if settings.get('default', True):
default_target = target
first_target = False
self._AddToolchain(target, setting_overrides=settings)
if default_target:
self._auto_default_toolchain = default_target
def _AddToolchain(self, target, setting_overrides=None):
"""Add a toolchain to |self|.
target: string target (e.g. 'x86_64-cros-linux-gnu').
setting_overrides: dictionary of setting overrides for this toolchain.
if setting_overrides is None:
setting_overrides = dict()
target=target, setting_overrides=setting_overrides))
def GetMergedToolchainSettings(self):
"""Returns a dictionary of merged toolchain settings."""
targets = {}
toolchains = copy.deepcopy(self._toolchains)
if not toolchains:
return targets
have_default = any([setting_overrides.get(_DEFAULT_TOOLCHAIN_KEY, False)
for target, setting_overrides in toolchains])
if not have_default:
assert self._auto_default_toolchain, 'No toolchains!?'
default_toolchain = _ToolchainTuple(self._auto_default_toolchain,
toolchains.insert(0, default_toolchain)
# We might get toolchain setting overrides from a couple different overlays.
# Merge all these overrides together, disallowing conflicts.
for toolchain in toolchains:
targets.setdefault(, dict())
existing_overrides = targets[]
for key, value in toolchain.setting_overrides.items():
if key in existing_overrides and existing_overrides[key] != value:
raise MismatchedToolchainConfigsError(
'For toolchain %s, found %s to be set to both %r and %r.' %
(, key, existing_overrides[key], value))
existing_overrides[key] = value
# Now that we've merged all the setting overrides, apply them to defaults.
for target in targets.keys():
settings = {
'sdk': True,
'crossdev': '',
'default': False,
targets[target] = settings
return targets