| # |
| # Copyright (C) 2016 The Android Open Source Project |
| # |
| # Licensed under the Apache License, Version 2.0 (the "License"); |
| # you may not use this file except in compliance with the License. |
| # You may obtain a copy of the License at |
| # |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, software |
| # distributed under the License is distributed on an "AS IS" BASIS, |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| # See the License for the specific language governing permissions and |
| # limitations under the License. |
| # |
| |
| """Toolchains util functions.""" |
| |
| |
| import glob |
| import os |
| import stat |
| |
| from environment import sysroot_util |
| import error |
| |
| |
| # TODO(b/27386504): Consider loading these from a cached envsetup. |
| # Where the prebuilt toolchain can be found (relative to OS path). |
| EXISTING_TOOLS_FORMAT = os.path.join('prebuilts', 'gcc', '{host_arch}') |
| # Where, under the existing tools dir, can tools be found for each arch. |
| ARCH_TOOL_PREFIX = { |
| 'x86': 'x86/x86_64-linux-android-4.9/bin/x86_64-linux-android-', |
| 'arm': 'arm/arm-linux-androideabi-4.9/bin/arm-linux-androideabi-' |
| } |
| # What default flags do we want tools to run with (default none). |
| TOOL_FLAGS = { |
| 'g++': ['-std=gnu++11', |
| '-fstack-protector-strong', |
| '-Wformat -Werror=format-security', |
| '-D_FORTIFY_SOURCE=2', |
| '-Werror=implicit-function-declaration', |
| '-fpie -pie', |
| '-Wl,-z,now', |
| '-isystem=' + os.path.join( |
| os.path.sep, sysroot_util.SysrootUtil.LIBCXX_INCLUDE_DIR)] |
| } |
| # Any architecture specific flags we want to be defaults. |
| ARCH_TOOL_FLAGS = { |
| 'x86': { |
| 'g++': ['-m32'] |
| }, |
| 'arm': { |
| 'g++': ['-marm'] |
| }, |
| 'mips': { |
| # TODO(b/27722530): get mips sysroot/toolchain working. |
| } |
| } |
| |
| |
| class Error(error.Error): |
| pass |
| |
| |
| class GenerationError(Error): |
| """Raised when the toolchain fails to generate correctly.""" |
| description = 'Failed to generate all tools' |
| |
| |
| def _ToolFlags(tool, arch): |
| """Helper to combine general and arch-specific tool flags.""" |
| result = [] |
| if tool in TOOL_FLAGS: |
| result += TOOL_FLAGS[tool] |
| if arch in ARCH_TOOL_FLAGS and tool in ARCH_TOOL_FLAGS[arch]: |
| result += ARCH_TOOL_FLAGS[arch][tool] |
| return result |
| |
| def _GenerateWrapper(src, dest, flags=None): |
| """Write a simple wrapper for a tool. |
| |
| dest will call src with flags. dest will be an executable file. |
| |
| Args: |
| src: The original tool to wrap. |
| dest: The place to put the wrapper. |
| flags: (optional) Flags to include in the wrapper. Default empty list. |
| |
| Raises: |
| OSError: There is an error opening or otherwise accessing dest. |
| IOError: There is an error writing the wrapper file. |
| """ |
| flags = flags or [] |
| with open(dest, 'w') as f: |
| f.write('#!/bin/sh\n{0} {1} "$@"\n'.format(src, ' '.join(flags))) |
| # Make sure the file is executable. |
| st = os.stat(dest) |
| os.chmod(dest, st.st_mode | stat.S_IEXEC) |
| |
| |
| def GenerateToolchain(platform, host, output_dir): |
| """Generate a toolchain. |
| |
| Args: |
| platform: Platform to generate toolchain for. |
| host: Host architecture to generate toolchain for. |
| output_dir: Where to put generated tools. |
| |
| Raises: |
| Error: Not all tools generated properly. |
| """ |
| # Make sure output dir exists. |
| if not os.path.isdir(output_dir): |
| os.makedirs(output_dir) |
| |
| # Put together some variables based on host and target. |
| existing_tools = platform.os.path( |
| EXISTING_TOOLS_FORMAT.format(host_arch=host)) |
| tool_prefix = os.path.join( |
| existing_tools, ARCH_TOOL_PREFIX[platform.device.arch]) |
| prefix_len = len(tool_prefix) |
| |
| # Walk the existing tools, wrapping them all. |
| errors = [] |
| for path in glob.iglob(tool_prefix + '*'): |
| # Skip dirs, not that there should be any. |
| if not os.path.isfile(path): |
| continue |
| |
| # Otherwise, assume it's a tool and wrap it. |
| tool = path[prefix_len:] |
| try: |
| output_tool = os.path.join(output_dir, tool) |
| tool_flags = _ToolFlags(tool, platform.device.arch) |
| # Write a simple wrapper. |
| _GenerateWrapper(path, output_tool, tool_flags) |
| except (IOError, OSError) as e: |
| errors.append((tool, e)) |
| |
| if errors: |
| raise GenerationError('Failed: {}'.format(errors)) |